home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2954 < prev    next >
Internet Message Format  |  1991-03-03  |  46KB

  1. From: lee@sq.sq.com (Liam R. E. Quin)
  2. Newsgroups: alt.sources
  3. Subject: lq-text Full Text Retrieval Database Part 06/13
  4. Message-ID: <1991Mar4.020500.16494@sq.sq.com>
  5. Date: 4 Mar 91 02:05:00 GMT
  6.  
  7. : cut here --- cut here --
  8. : To unbundle, sh this file
  9. #! /bin/sh
  10. : part 06
  11. echo x - lq-text/src/liblqtext/progname.c 1>&2
  12. sed 's/^X//' >lq-text/src/liblqtext/progname.c <<'@@@End of lq-text/src/liblqtext/progname.c'
  13. X/* progname.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
  14. X * This code is NOT in the public domain.
  15. X * See the file COPYRIGHT for full details.
  16. X * This file simply declares progname.
  17. X * This variable MUST be set by main().
  18. X */
  19. X
  20. Xchar *progname = (char *) 0;
  21. X
  22. X/* $Id: progname.c,v 1.2 90/10/06 00:12:19 lee Rel1-10 $
  23. X *
  24. X * $Log:    progname.c,v $
  25. X * Revision 1.2  90/10/06  00:12:19  lee
  26. X * Prepared for first beta release.
  27. X * 
  28. X * Revision 1.1  90/03/24  17:07:22  lee
  29. X * Initial revision
  30. X * 
  31. X *
  32. X */
  33. @@@End of lq-text/src/liblqtext/progname.c
  34. echo x - lq-text/src/liblqtext/smalldb.c 1>&2
  35. sed 's/^X//' >lq-text/src/liblqtext/smalldb.c <<'@@@End of lq-text/src/liblqtext/smalldb.c'
  36. X/* smalldb.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
  37. X * This code is NOT in the public domain.
  38. X * See the file COPYRIGHT for full details.
  39. X */
  40. X
  41. X/* Simple interface to start and end dbm.
  42. X * You may also need to supply dbm_store() and dbm_fetch(), but these
  43. X * should certainly be macros.
  44. X *
  45. X * $Id: smalldb.c,v 1.5 91/03/03 00:15:22 lee Rel1-10 $
  46. X *
  47. X * $Log:    smalldb.c,v $
  48. X * Revision 1.5  91/03/03  00:15:22  lee
  49. X * Improved an error message and fixed a permissions bug.
  50. X * 
  51. X * Revision 1.4  91/03/02  18:52:48  lee
  52. X * Default access is now read only -- lqWriteAccess must be called otherwise.
  53. X * 
  54. X * Revision 1.3  90/10/06  00:12:20  lee
  55. X * Prepared for first beta release.
  56. X * 
  57. X * Revision 1.2  90/09/20  17:53:26  lee
  58. X * slight error reporting improvement.
  59. X * 
  60. X * Revision 1.1  90/08/09  19:16:56  lee
  61. X * Initial revision
  62. X * 
  63. X * Revision 2.2  89/10/08  20:47:14  lee
  64. X * Working version of nx-text engine.  Addfile and wordinfo work OK.
  65. X * 
  66. X * Revision 2.1  89/10/02  01:15:55  lee
  67. X * New index format, with Block/WordInBlock/Flags/BytesSkipped info.
  68. X * 
  69. X * Revision 1.2  89/09/16  21:18:39  lee
  70. X * First demonstratable version.
  71. X * 
  72. X * Revision 1.1  89/09/07  21:06:11  lee
  73. X * Initial revision
  74. X * 
  75. X *
  76. X */
  77. X
  78. X#include "globals.h"
  79. X
  80. X#include <stdio.h>
  81. X
  82. X#include <fcntl.h>
  83. X#ifdef BSD
  84. X# include <sys/param.h>
  85. X# define PATH_MAX MAXPATHLEN /* untested, sorry */
  86. X#else /*!BSD*/
  87. X# include <limits.h> /* for PATH_MAX */
  88. X#endif
  89. X#include "smalldb.h"
  90. X#include "emalloc.h"
  91. X
  92. Xextern int strcmp();
  93. Xextern char *strcpy();
  94. X
  95. X/* The physical database for the list of words, and for the list
  96. X * of files, uses ndbm.
  97. X * The advantage of this is that it takes only two file system accesses
  98. X * to retrieve any data item (honest!).
  99. X * It's also reasonably fast at insertion.
  100. X * One disadvantage is that it doesn't cope if too many words have the
  101. X * same (32-bit) hash function, although publicly available replacements
  102. X * such as the GNU project's gdbm fix this.
  103. X *
  104. X * Since starting the database is expensive (two opens and a malloc),
  105. X * I have a cache of DBM pointers and keep them open.  Versions of the
  106. X * dbm routines that don't support more than one database will have to
  107. X * have a cache-size of one!
  108. X * I am not sure what the impact of this would be on performance; for
  109. X * adding a new file it shouldn't be too bad, as the file list is examined
  110. X * only once for each file, during reading, and the word database is looked
  111. X * at (at least once for each distinct word) only on writing.
  112. X * For retrieval, however, the word database will be looked at for each
  113. X * word in the query, and the file database for (potentially) each match
  114. X * of each word, so the requests will be more interspersed.
  115. X * Under no circumstances is it acceptable to dispense with the cache, as
  116. X * otherwise you will be doing (literally) thousands of calls to
  117. X * open() and close() per second!
  118. X *
  119. X */
  120. X
  121. X#undef startdb
  122. X
  123. X#ifndef CACHE
  124. X/* It's unusual to deal with lots of databases at once, so let's not
  125. X * waste RAM...
  126. X */
  127. X# define CACHE 3
  128. X#endif
  129. X
  130. Xstatic char NameCache[CACHE][PATH_MAX + 1]; /* + 1 for \0, I think */
  131. Xstatic DBM *Cache[CACHE]; /* (set to zero by definition) */
  132. X
  133. Xstatic int MaxInCache = (-1);
  134. X
  135. X/* FileFlags and Mode are passed to dbm_open */
  136. Xstatic int FileFlags = O_RDONLY;
  137. Xstatic int FileModes = 0;
  138. X
  139. Xvoid
  140. XlqWriteAccess()
  141. X{
  142. X    FileFlags = O_RDWR|O_CREAT;
  143. X    FileModes = 0664; /* owner and group write, others read only */
  144. X}
  145. X
  146. XDBM *
  147. Xstartdb(FilePrefix)
  148. X    char *FilePrefix;
  149. X{
  150. X    extern int errno;
  151. X    register int i;
  152. X
  153. X    for (i = 0; i <= MaxInCache; i++) {
  154. X    if (Cache[i] && STREQ(NameCache[i], FilePrefix)) {
  155. X        return Cache[i];
  156. X    }
  157. X    }
  158. X
  159. X    /* Find an empty slot */
  160. X    for (i = 0; i <= MaxInCache; i++) {
  161. X    if (Cache[i] == (DBM *) 0) break;
  162. X    }
  163. X
  164. X    if (i > MaxInCache) {
  165. X    if (i >= CACHE) i = 0;
  166. X    }
  167. X
  168. X    if (Cache[i]) dbm_close(Cache[i]);
  169. X    NameCache[i][0] = '\0';
  170. X
  171. X    errno = 0;
  172. X
  173. X    if ((Cache[i] = dbm_open(FilePrefix, FileFlags, FileModes)) == (DBM *)0) {
  174. X    int e = errno;
  175. X    (void) fprintf(stderr, "%s: dbm_open error %d: ", progname, errno);
  176. X    errno = e;
  177. X    perror(FilePrefix);
  178. X    exit(1);
  179. X    }
  180. X    (void) strcpy(NameCache[i], FilePrefix);
  181. X    if (i > MaxInCache) MaxInCache = i;
  182. X
  183. X    return Cache[i];
  184. X}
  185. X
  186. X#undef enddb
  187. X
  188. X/*ARGSUSED*/
  189. Xvoid
  190. Xenddb(db)
  191. X    DBM *db;
  192. X{
  193. X    /* no-op */
  194. X}
  195. X
  196. Xvoid
  197. Xcleanupdb()
  198. X{
  199. X    register int i;
  200. X
  201. X    for (i = 0; i <= MaxInCache; i++) {
  202. X    if (Cache[i]) dbm_close(Cache[i]);
  203. X    Cache[i] = (DBM *) 0;
  204. X    NameCache[i][0] = '\0';
  205. X    }
  206. X}
  207. @@@End of lq-text/src/liblqtext/smalldb.c
  208. echo x - lq-text/src/liblqtext/system.c 1>&2
  209. sed 's/^X//' >lq-text/src/liblqtext/system.c <<'@@@End of lq-text/src/liblqtext/system.c'
  210. X/* system.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
  211. X * This code is NOT in the public domain.
  212. X * See the file COPYRIGHT for full details.
  213. X *
  214. X * This is not a very portable way of doing things... and certainly not
  215. X * a very fast one.  MUST be re-written.
  216. X * Only for use from within curses.
  217. X *
  218. X * Lee
  219. X *
  220. X * $Id: system.c,v 1.3 90/10/06 00:21:37 lee Rel1-10 $
  221. X */
  222. X
  223. X#ifdef ultrix
  224. X# include <cursesX.h>
  225. X#else
  226. X# include <curses.h>
  227. X#endif
  228. X
  229. X#ifndef echo
  230. Xextern int echo();
  231. X#endif
  232. X#ifndef wmove
  233. Xextern int wmove();
  234. X#endif
  235. X#ifndef nl
  236. Xextern int nl();
  237. X#endif
  238. X#ifndef noecho
  239. Xextern int noecho();
  240. X#endif
  241. X#ifndef nonl
  242. Xextern int nonl();
  243. X#endif
  244. X#ifndef wrefresh
  245. Xextern int wrefresh();
  246. X#endif
  247. X#ifndef waddstr
  248. Xextern int waddstr();
  249. X#endif
  250. X#ifndef wclear
  251. Xextern int wclear();
  252. X#endif
  253. X
  254. Xint
  255. XMySystem(string)
  256. X    char *string;
  257. X{
  258. X    int val;
  259. X
  260. X    clearok(stdscr, TRUE);
  261. X    clear();
  262. X    refresh();
  263. X    noraw();
  264. X    echo();
  265. X    nl();
  266. X    val = system("stty opost icanon onlcr icrnl echo");
  267. X    (void) system(string);
  268. X    fprintf(stderr, "\n[press  return  to continue] ");
  269. X    raw();
  270. X    noecho();
  271. X    nonl();
  272. X    (void) getch();
  273. X    clearok(stdscr, TRUE);
  274. X    mvwaddstr(stdscr, 10, 10, "                        "); /* ???!?? */
  275. X
  276. X    return val;
  277. X}
  278. X
  279. @@@End of lq-text/src/liblqtext/system.c
  280. echo x - lq-text/src/lqtext/FindCommon.sh 1>&2
  281. sed 's/^X//' >lq-text/src/lqtext/FindCommon.sh <<'@@@End of lq-text/src/lqtext/FindCommon.sh'
  282. X:
  283. X# FindCommon -- Copyright 1990 Liam R. Quin.  All Rights Reserved.
  284. X# This code is NOT in the public domain.
  285. X# See the file COPYRIGHT for full details.
  286. X#
  287. X# $Id: FindCommon.sh,v 1.2 90/10/06 00:50:31 lee Rel1-10 $
  288. X
  289. X# Find the most common words in the database.
  290. X# usage is % n, where n is the n most comon words to find
  291. X
  292. Xlqword -a | sed -e 's/^......................\(.........\)..\(..*\)$/\1    \2/' |
  293. Xsort -nr | sed ${1-500}q
  294. X
  295. Xexit $?
  296. X
  297. X#         1 |       0 |       2 | pcpaintbrush
  298. X#         2 |       0 |       2 | escape
  299. X#         3 |       0 |       1 | durham
  300. X#         4 |   60928 |      12 | making
  301. X#         5 |       0 |       1 | ethical
  302. X#         6 |       0 |       1 | committing
  303. X
  304. X# $Log:    FindCommon.sh,v $
  305. X# Revision 1.2  90/10/06  00:50:31  lee
  306. X# Prepared for first beta release.
  307. X# 
  308. X#
  309. @@@End of lq-text/src/lqtext/FindCommon.sh
  310. echo x - lq-text/src/lqtext/Makefile 1>&2
  311. sed 's/^X//' >lq-text/src/lqtext/Makefile <<'@@@End of lq-text/src/lqtext/Makefile'
  312. X# Makefile for LQ-Text, a full text retrieval package by Liam R. Quin
  313. X# This Makefile belongs in the "src/lqtext" directory.
  314. X#
  315. X# Note that most of the actual configuration is done in ../Makefile and
  316. X# in ../h/global.h, and not here.
  317. X
  318. X# Makefile -- Copyright 1990 Liam R. Quin.  All Rights Reserved.
  319. X# This code is NOT in the public domain.
  320. X# See the file ../COPYRIGHT for full details.
  321. X#
  322. X# $Id: Makefile,v 1.5 91/03/03 00:19:26 lee Rel1-10 $
  323. X
  324. X
  325. XPWD=lqtext
  326. X
  327. XTARGETS = lqaddfile lqfile lqword lqphrase lqshow lqkwik lq
  328. XBINFILES =lqaddfile lqfile lqword lqshow lqphrase lqkwik
  329. X
  330. XDESTDIR=../bin
  331. XMODE=755
  332. XRANLIB=echo
  333. X
  334. XEXTRA=-I../h
  335. X
  336. Xall: $(TARGETS)
  337. X
  338. X# for ndbm (simplest), leave empty or use -lndbm if you need it
  339. X# for sdbm (best so far), use ../lib/libsdbm.a
  340. X# for gdbm... well, I dunno.
  341. XDBMLIBS=../lib/libsdbm.a
  342. X# DBMLIBS=-lndbm
  343. X# DBMLIBS=ndbm.o bcopy.o
  344. X
  345. XTEXTLIB=../lib/liblqtext.a ../lib/liblq.a
  346. X
  347. X# The following are for "make depend" and for sabre to load...
  348. XDEPENDFILES = ReadAhead.c SixBit.c fileindex.c lqaddfile.c lqphrase.c \
  349. X          lqshow.c lqword.c sizes.c wordtable.c
  350. X
  351. X# MALLFILES=/usr/lib/debug/malloc.o /usr/lib/debug/mallocmap.o
  352. XMALLFILES = 
  353. X
  354. Xinstall: all
  355. X    for i in $(BINFILES); do cp "$$i" $(DESTDIR); \
  356. X    strip "$(DESTDIR)/$$i" ; \
  357. X    done ; \
  358. X    mv lq $(DESTDIR)/lq; chmod $(MODE) $(DESTDIR)/lq;
  359. X
  360. X.SUFFIXES: .c .o .src .obj
  361. X
  362. X.c.src:
  363. X    #load $(CFLAGS) $<
  364. X
  365. X.o.obj:
  366. X    #load $(CFLAGS) $<
  367. X
  368. X# If you are going to use saber on these, you should name the programs.
  369. Xsaber_src:
  370. X
  371. Xsaber_obj:
  372. X
  373. Xlq: lq.sh
  374. X    cp lq.sh lq
  375. X    chmod +x lq
  376. X
  377. Xlqshow: lqshow.o $(TEXTLIB)
  378. X    $(CC) $(CFLAGS) -o lqshow lqshow.o $(TEXTLIB) $(TERMCAP) $(DBMLIBS)
  379. X
  380. Xlqaddfile: lqaddfile.o wordtable.o $(TEXTLIB)
  381. X    $(CC) $(CFLAGS) -o lqaddfile lqaddfile.o wordtable.o \
  382. X            $(TEXTLIB) $(MALLOC) $(DBMLIBS) $(MALLFILES)
  383. X
  384. Xlqfile: fileindex.o $(TEXTLIB)
  385. X    $(CC) $(CFLAGS) -o lqfile fileindex.o $(TEXTLIB) $(MALLOC) $(DBMLIBS)
  386. X    
  387. Xlqword: lqword.o $(TEXTLIB)
  388. X    $(CC) $(CFLAGS) -o lqword lqword.o $(TEXTLIB) $(MALLOC) $(DBMLIBS)
  389. X
  390. Xlqkwik: lqkwik.o $(TEXTLIB)
  391. X    $(CC) $(CFLAGS) -o lqkwik lqkwik.o $(TEXTLIB) $(MALLOC) $(DBMLIBS)
  392. X
  393. Xlqphrase: lqphrase.o $(TEXTLIB)
  394. X    $(CC) $(CFLAGS) -o lqphrase lqphrase.o $(TEXTLIB) $(DBMLIBS)
  395. X
  396. Xlint: AddFile.Lint News.Lint FileInfo.Lint Phrase.Lint
  397. X
  398. Xtidy:
  399. X    /bin/rm -f *.o core
  400. X
  401. Xclean: tidy
  402. X    /bin/rm -f $(TARGETS) $(TEST)
  403. X
  404. Xdepend:
  405. X    mkdep $(CFLAGS) *.c
  406. X
  407. X#
  408. X# $Log:    Makefile,v $
  409. X# Revision 1.5  91/03/03  00:19:26  lee
  410. X# added lqkwik
  411. X# 
  412. X# Revision 1.4  90/10/06  00:50:42  lee
  413. X# Prepared for first beta release.
  414. X# 
  415. X# Revision 1.3  90/10/05  23:54:57  lee
  416. X# deleted mkdep output.
  417. X# 
  418. X# Revision 1.2  90/09/28  21:54:01  lee
  419. X# No longer uses OWNER.
  420. X# 
  421. X# Revision 1.1  90/08/09  19:17:39  lee
  422. X# Initial revision
  423. X# 
  424. X# DO NOT DELETE THIS LINE -- mkdep uses it.
  425. X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
  426. X
  427. XSixBit.o: SixBit.c ../h/globals.h 
  428. XSixBit.o: ../h/wordrules.h
  429. Xfileindex.o: fileindex.c ../h/globals.h 
  430. Xfileindex.o: ../h/emalloc.h ../h/fileinfo.h
  431. Xlqaddfile.o: lqaddfile.c 
  432. Xlqaddfile.o: ../h/globals.h ../h/fileinfo.h ../h/emalloc.h
  433. Xlqaddfile.o: ../h/wordinfo.h ../h/pblock.h ../h/wordrules.h ../h/filter.h
  434. Xlqkwik.o: lqkwik.c ../h/globals.h ../h/fileinfo.h
  435. Xlqkwik.o: ../h/wordinfo.h ../h/pblock.h ../h/wordrules.h ../h/pblock.h
  436. Xlqkwik.o: ../h/emalloc.h
  437. Xlqphrase.o: lqphrase.c ../h/globals.h ../h/emalloc.h
  438. Xlqphrase.o: ../h/fileinfo.h ../h/wordinfo.h ../h/pblock.h ../h/pblock.h
  439. Xlqphrase.o: ../h/phrase.h
  440. Xlqshow.o: lqshow.c ../h/globals.h
  441. Xlqword.o: lqword.c ../h/globals.h 
  442. Xwordtable.o: wordtable.c ../h/globals.h
  443. X
  444. X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
  445. @@@End of lq-text/src/lqtext/Makefile
  446. echo x - lq-text/src/lqtext/ReadAhead.c 1>&2
  447. sed 's/^X//' >lq-text/src/lqtext/ReadAhead.c <<'@@@End of lq-text/src/lqtext/ReadAhead.c'
  448. @@@End of lq-text/src/lqtext/ReadAhead.c
  449. echo x - lq-text/src/lqtext/fileindex.c 1>&2
  450. sed 's/^X//' >lq-text/src/lqtext/fileindex.c <<'@@@End of lq-text/src/lqtext/fileindex.c'
  451. X/* fileindex.c -- Copyright 1989, 1990 Liam R. Quin.  All Rights Reserved.
  452. X * This code is NOT in the public domain.
  453. X * See the file COPYRIGHT for full details.
  454. X */
  455. X
  456. X/* A simple program to give information about one or more files about
  457. X * which information is stored in the NX-Text database.
  458. X *
  459. X * $Id: fileindex.c,v 1.4 91/03/02 18:56:53 lee Rel1-10 $
  460. X */
  461. X
  462. X#include "globals.h" /* defines and declarations for database filenames */
  463. X
  464. X#include <stdio.h>
  465. X#include <sys/types.h>
  466. X#include <malloc.h>
  467. X#include "emalloc.h"
  468. X#include "fileinfo.h"
  469. X
  470. Xstatic char *Revision = "@(#) lqtext 2.3 89/11/34";
  471. X
  472. X/* The position of the \n in the 26-char string returned by ctime(3): */
  473. X#define DATENEWLINE 24
  474. X
  475. Xchar *progname;
  476. Xint AsciiTrace = 0;
  477. X
  478. X/** System calls and library functions used in this file: **/
  479. X
  480. X/** Unix System calls: **/
  481. Xextern void exit();
  482. X/** System Library Functions: **/
  483. X
  484. X/** external lqtext functions: **/
  485. Xextern void cleanupdb(), SetDefaults();
  486. Xint SaveFileInfo(), GetFilterType();
  487. X#ifndef efree
  488. X extern void efree();
  489. X#endif
  490. X/** Functions defined within this file: **/
  491. Xvoid AddInfo(), AllInfo(), Display(), PrintInfo();
  492. X
  493. Xint AllFiles = 0;
  494. Xint ListMode = 0;
  495. Xint AddFiles = 0;
  496. X
  497. Xint
  498. Xmain(argc, argv)
  499. X    int argc;
  500. X    char *argv[];
  501. X{
  502. X    extern int optind, getopt();
  503. X    /** extern char *optarg; (unused at the moment) **/
  504. X    int ch;
  505. X    int ErrorFlag = 0;
  506. X
  507. X    progname = argv[0];
  508. X
  509. X    SetDefaults(argc, argv);
  510. X
  511. X    /* All programs take Zz:Vv */
  512. X    while ((ch = getopt(argc, argv, "Zz:VvAax")) != EOF) {
  513. X    switch (ch) {
  514. X    case 'z':
  515. X    case 'Z':
  516. X        break; /* done by SetDefaults(); */
  517. X    case 'V':
  518. X        fprintf(stderr, "%s version %s\n", progname, Revision);
  519. X        break;
  520. X    case 'v':
  521. X        AsciiTrace = 1;
  522. X        break;
  523. X    case 'A':
  524. X        AddFiles = 1;
  525. X        break;
  526. X    case 'a':
  527. X        AllFiles = 1;
  528. X        break;
  529. X    case 'l':
  530. X        ListMode = 1;
  531. X        break;
  532. X    case 'x':
  533. X        ErrorFlag = (-1);
  534. X        break;
  535. X    case '?':
  536. X        ErrorFlag = 1;
  537. X        break;
  538. X    }
  539. X    }
  540. X
  541. X    /* Normally put call to lrqError here to give a helpful message,
  542. X     * but not yet ready to ship the error handling package, sorry
  543. X     */
  544. X    if (ErrorFlag) {
  545. X    fprintf(stderr, "%s: usage: %s [options] [files]\n",progname,progname);
  546. X    fprintf(stderr, "%s: options are:\n", progname);
  547. X    fputs("\
  548. X    -c file -- treat the named file as a list of common words\n\
  549. X    -d dir    -- use the lq-text database in the directory \"dir\"\n\
  550. X    -l    -- list mode: no header output or lines drawn\n\
  551. X    -s    -- show the list of saved files\n\
  552. X    -t N    -- set trace level to N [default: 0]\n\
  553. X    -V    -- print version information\n\
  554. X    -v    -- be verbose (same as -t 1)\n\
  555. X    -x    -- print this explanation\n\
  556. X\n\
  557. XIn addition, if no files are given, the following are understood:\n\
  558. X    -A    -- add the named files to the list of known files\n\
  559. X    -a    -- list information about all files\n", stderr);
  560. X    exit((ErrorFlag > 0) ? 1 : 0);
  561. X    }
  562. X
  563. X    if (AllFiles && AddFiles) {
  564. X    fprintf(stderr, "%s: do not use both -a and -A options\n", progname);
  565. X    fprintf(stderr, "\tuse %s -x for further explanation.\n", progname);
  566. X    exit(1);
  567. X    }
  568. X
  569. X    if (optind >= argc && !AllFiles && !AddFiles) {
  570. X    fprintf(stderr,
  571. X    "%s: You must either give the -a option or specify files to list.\n",
  572. X        progname);
  573. X    fprintf(stderr, "\tuse %s -x for further explanation.\n", progname);
  574. X    exit(1);
  575. X    }
  576. X
  577. X    if (!AddFiles || !ListMode) {
  578. X    printf("%-7.7s | T | %-20.20s | %s\n",
  579. X        "FID", "Date Last indexed", "Current Location");
  580. X    puts(
  581. X"========|===|======================|=========================================="
  582. X    );
  583. X    }
  584. X    if (AllFiles) {
  585. X    AllInfo();
  586. X    } else {
  587. X    if (AddFiles) {
  588. X        extern lqWriteAccess();
  589. X
  590. X        lqWriteAccess();
  591. X    }
  592. X
  593. X    while (optind < argc) {
  594. X        if (AddFiles) {
  595. X        AddInfo(argv[optind++]);
  596. X        } else {
  597. X        PrintInfo(argv[optind++]); /* ugh */
  598. X        }
  599. X    }
  600. X    }
  601. X    cleanupdb(); /* close dbm files */
  602. X    exit(0);
  603. X    /*NOTREACHED*/
  604. X    return 1; /* for lint and gcc... */
  605. X}
  606. X
  607. Xvoid
  608. XPrintInfo(Name)
  609. X    char *Name;
  610. X{
  611. X    extern t_FileInfo *GetFileInfo();
  612. X    long FID;
  613. X    extern long atol();
  614. X    extern t_FID Name2FID();
  615. X
  616. X    t_FileInfo *FileInfo;
  617. X
  618. X    if ((FID = Name2FID(Name)) == (t_FID) 0) {
  619. X    fprintf(stderr, "No FID information for filename: %s\n", Name);
  620. X        if ((FID = atol(Name)) == (t_FID) 0) {
  621. X        return;
  622. X    }
  623. X    }
  624. X
  625. X    /* get info from the list */
  626. X    if ((FileInfo = GetFileInfo(FID)) == (t_FileInfo *) 0) {
  627. X    fprintf(stderr, "No index information for: %s\n", Name);
  628. X    return;
  629. X    }
  630. X    Display(FileInfo);
  631. X}
  632. X
  633. Xvoid
  634. XDisplay(FileInfo)
  635. X    t_FileInfo *FileInfo;
  636. X{
  637. X    extern char *ctime();
  638. X    char *DateString;
  639. X
  640. X    DateString = ctime(&(FileInfo->Date));
  641. X    DateString[DATENEWLINE] = '\0'; /* delete the trailing newline */
  642. X
  643. X    if (ListMode) {
  644. X    printf("%lu %d %s %s\n",
  645. X    FileInfo->FID, FileInfo->FilterType, &DateString[4], FileInfo->Name);
  646. X    } else {
  647. X    printf("%7lu | %d | %-20.20s | %s\n",
  648. X        FileInfo->FID, FileInfo->FilterType, &DateString[4], FileInfo->Name);
  649. X    }
  650. X}
  651. X
  652. X/**
  653. XMon Sep 25 23:58:53 BST 1989
  654. XFID     | T | Date Last indexed    | Current Location
  655. X========|===|======================|===========================================
  656. X      1 | 0 | Sep 25 20:31:26 1989 | /usr2/liam/Bible/NT/John/john01.kjv
  657. X      2 | 0 | Sep 25 20:31:28 1989 | /usr2/liam/Bible/NT/John/john02.kjv
  658. X      3 | 0 | Sep 25 20:31:30 1989 | /usr2/liam/Bible/NT/John/john03.kjv
  659. X**/
  660. X
  661. Xvoid
  662. XAllInfo()
  663. X{
  664. X    extern long GetMaxFID();
  665. X    extern t_FileInfo *GetFileInfo();
  666. X
  667. X    t_FileInfo *FileInfo;
  668. X    long FID;
  669. X    long MaxFid = GetMaxFID();
  670. X
  671. X    for (FID = 0L; FID <= MaxFid; FID++) {
  672. X    if ((FileInfo = GetFileInfo(FID)) != (t_FileInfo *) 0) {
  673. X        Display(FileInfo);
  674. X        efree(FileInfo); /* NOTDONE use destroyfileinfo() */
  675. X    }
  676. X    }
  677. X    printf("Max File Identifier is %lu\n", MaxFid);
  678. X}
  679. X
  680. Xvoid
  681. XAddInfo(FileName)
  682. X    char *FileName;
  683. X{
  684. X    extern time_t time();
  685. X    extern unsigned long GetNextFID();
  686. X    t_FileInfo FileInfo;
  687. X
  688. X    FileInfo.Name = FileName;
  689. X    (void) time(&(FileInfo.Date));
  690. X    FileInfo.FID = GetNextFID();
  691. X    FileInfo.Stream = 0; /* force GetFilterType to use open()? */
  692. X
  693. X    /* determine filter type */
  694. X    FileInfo.FilterType = GetFilterType(&FileInfo);
  695. X
  696. X    printf("%d %s (type %d) %s\n",
  697. X        FileInfo.FID,
  698. X        FileInfo.Name,
  699. X        FileInfo.FilterType,
  700. X        SaveFileInfo(&FileInfo) == 0 ?
  701. X                "saved successfully." :
  702. X                "not saved."
  703. X    );
  704. X}
  705. X
  706. X/*
  707. X * $Log:    fileindex.c,v $
  708. X * Revision 1.4  91/03/02  18:56:53  lee
  709. X * Now asks for write access iff [sic] necessary
  710. X * 
  711. X * Revision 1.3  90/10/06  00:50:50  lee
  712. X * Prepared for first beta release.
  713. X * 
  714. X * Revision 1.2  90/08/29  21:44:51  lee
  715. X * Alpha release
  716. X * 
  717. X * Revision 1.1  90/08/09  19:17:11  lee
  718. X * Initial revision
  719. X * 
  720. X * Revision 2.2  89/10/08  20:45:46  lee
  721. X * Working version of nx-text engine.  Addfile and wordinfo work OK.
  722. X * 
  723. X * Revision 2.1  89/10/02  01:14:18  lee
  724. X * New index format, with Block/WordInBlock/Flags/BytesSkipped info.
  725. X * 
  726. X * Revision 1.2  89/09/16  21:16:17  lee
  727. X * First demonstratable version.
  728. X * 
  729. X * Revision 1.1  89/09/07  21:05:55  lee
  730. X * Initial revision
  731. X *
  732. X */
  733. @@@End of lq-text/src/lqtext/fileindex.c
  734. echo x - lq-text/src/lqtext/intersect.sh 1>&2
  735. sed 's/^X//' >lq-text/src/lqtext/intersect.sh <<'@@@End of lq-text/src/lqtext/intersect.sh'
  736. X:
  737. X# intersect word-one word-two
  738. X#
  739. X# intersect -- Copyright 1990 Liam R. Quin.  All Rights Reserved.
  740. X# This code is NOT in the public domain.
  741. X# See the file ../COPYRIGHT for full details.
  742. X#
  743. X# $Id: intersect.sh,v 1.3 91/03/03 00:18:59 lee Rel1-10 $
  744. X#
  745. X
  746. X
  747. XFileNumber=0
  748. XFileList=
  749. XProgram=lqphrase
  750. XProgOpts=
  751. XAll=/tmp/iAll$$
  752. Xexport All
  753. X
  754. Xtrap '/bin/rm -f $All $tmp $First $FileList; exit' 0 1 2 3 15
  755. X
  756. Xif [ x"$1" = x"" ]
  757. Xthen
  758. X    echo "$0: Usage: `basename $0` {-w word} | {-p phrase} ..." 1>&2
  759. X    exit 1
  760. Xfi
  761. X
  762. X
  763. Xfor i
  764. Xdo
  765. X    if [ x"$i" = x"-p" ]
  766. X    then
  767. X    Program=lqphrase
  768. X    ProgOpts=
  769. X    elif [ x"$i" = x"-w" ]
  770. X    then
  771. X    Program=lqword
  772. X    ProgOpts=-l
  773. X    else
  774. X    tmp=/tmp/inter.$FileNumber
  775. X    $Program $ProgOpts "$i" | tee -a $ALL | awk '{ print $3 }' | sort -u > $tmp
  776. X    if [ x"$First" = x"" ]
  777. X    then
  778. X        First="$tmp"
  779. X    else
  780. X        FileList="$FileList $tmp"
  781. X    fi
  782. X    FileNumber=`expr $FileNumber + 1`
  783. X    fi
  784. Xdone
  785. X
  786. X# Find matches...
  787. Xtmp=/tmp/inter.tmp$$
  788. X
  789. Xfor i in $FileList
  790. Xdo
  791. X    fgrep -x -f $First $i | sort -u > $tmp
  792. X    mv $tmp $First
  793. Xdone
  794. X
  795. Xmv $First $tmp
  796. Xsed 's/^/ /' $tmp > $First
  797. X
  798. Xfgrep -f $First $All
  799. Xexit 0
  800. X
  801. X#
  802. X#
  803. X# $Log:    intersect.sh,v $
  804. X# Revision 1.3  91/03/03  00:18:59  lee
  805. X# brought up to date a little...
  806. X# 
  807. X# Revision 1.2  90/10/06  00:50:52  lee
  808. X# Prepared for first beta release.
  809. X# 
  810. X# Revision 1.1  90/08/29  21:45:01  lee
  811. X# Initial revision
  812. X# 
  813. X#
  814. X#
  815. @@@End of lq-text/src/lqtext/intersect.sh
  816. echo x - lq-text/src/lqtext/lq.sh 1>&2
  817. sed 's/^X//' >lq-text/src/lqtext/lq.sh <<'@@@End of lq-text/src/lqtext/lq.sh'
  818. X#! /bin/sh
  819. X: use /bin/sh
  820. X# put the : line first on System V
  821. X
  822. X# lq -- Copyright 1990 Liam R. Quin.  All Rights Reserved.
  823. X# This code is NOT in the public domain.
  824. X# See the file ../COPYRIGHT for full details.
  825. X#
  826. X# $Id: lq.sh,v 1.3 90/10/06 00:50:53 lee Rel1-10 $
  827. X#
  828. X
  829. Xif [ x"`echo -n hello`" = x'hello' ]
  830. Xthen
  831. X    N=-n
  832. X    C=
  833. Xelse
  834. X    N=
  835. X    C='\c'
  836. Xfi
  837. X
  838. Xquit=no
  839. Xt=/tmp/lq$$
  840. XListFile=/tmp/lqshow$$
  841. Xexport ListFile
  842. X
  843. Xtrap '/bin/rm -f $t; exit' 0 1 2 3 15
  844. X
  845. X
  846. Xwhile  [ x"$quit" != x"yes" ]
  847. Xdo
  848. X    cat << boy
  849. X| Type a words or phrases to find, one per line,
  850. X| and then press return.
  851. Xboy
  852. X    x='fhdjfd'
  853. X    Phrases=
  854. X    while [ x"$x" != x"" ]
  855. X    do
  856. X    echo $N "| $C"
  857. X    read x
  858. X    if [ x"$x" != x"" ]
  859. X    then
  860. X        New=`echo "$x" | sed 's/"/:/g'`
  861. X        Phrases="${Phrases} \"$x\""
  862. X    fi
  863. X    done
  864. X    echo $Phrases
  865. X    eval lqphrase -p $Phrases \> $t
  866. X    if [ ! -s $t ]
  867. X    then
  868. X    echo "No match"
  869. X    else
  870. X    # determine the order in which matches will be presented to the user:
  871. X    sort +2 -o "$t" "$t" # (this is our ranking function)
  872. X    # (it only makes a difference if there was more than one phrase)
  873. X
  874. X    # Now some arcanery, I'm afraid...  The trick is that lqshow can be
  875. X    # given the name of a file descriptor in which to save the names of
  876. X    # any files the user selects (with "s").
  877. X    old_t="$t"
  878. X    t="$t ${ListFile}"
  879. X    lqshow -o 3 -f $t 3>> ${ListFile}
  880. X    t="$old_t"
  881. X    if [ -s ${ListFile} ]
  882. X    then ## the user typed s/k/whatever to save some files...
  883. X        # make the list by interpreting the list file:
  884. X        LIST=`awk '
  885. X        /^#.*$/ { next }
  886. X        ($1 == "s") { SAVE[$2]++ }
  887. X        ($1 == "d") { SAVE[$2] = 0 }
  888. X        END {
  889. X        for (i in SAVE) {
  890. X            if (SAVE[i] > 0) print i
  891. X        }
  892. X        }' $ListFile | sort -u`
  893. X        # make a new list file...
  894. X        echo "$LIST" | sed '/^[     ]*$/d' > $ListFile
  895. X        LIST="" # save memory
  896. X    fi
  897. X    # now see if it's still non-empty...
  898. X    if [ -s ${ListFile} ]
  899. X    then
  900. X        List="Type S filename to save the list of files (s also quits) "
  901. X    else
  902. X        /bin/rm -f ${ListFile}
  903. X    fi
  904. X    fi
  905. X    echo $List
  906. X    echo $N "Type q to quit, or return to continue: $C"
  907. X    read quit rest
  908. X    case "$quit" in
  909. X    [qQ]*) quit="yes" ;;
  910. X    [sS]) # save the list of matches
  911. X    cat $ListFile
  912. X
  913. X    if [ ! -s "$ListFile" ]
  914. X    then
  915. X        echo "No files in the list to save."
  916. X        quit=no
  917. X    else
  918. X        if [ -z "$rest" ]
  919. X        then rest="lq.list"
  920. X        fi
  921. X
  922. X        if [ -f "$rest" ]
  923. X        then echo "Appending to existing file $rest"
  924. X        fi
  925. X
  926. X        cat $ListFile >> $rest
  927. X        rm $ListFile
  928. X        if [ x"$quit" = x"s" ]
  929. X        then quit=yes
  930. X        else quit=no
  931. X        fi
  932. X    fi
  933. X    ;;
  934. X    *)       quit=no ;;
  935. X    esac
  936. Xdone
  937. X
  938. X#
  939. X# $Log:    lq.sh,v $
  940. X# Revision 1.3  90/10/06  00:50:53  lee
  941. X# Prepared for first beta release.
  942. X# 
  943. X#
  944. X#
  945. @@@End of lq-text/src/lqtext/lq.sh
  946. echo x - lq-text/src/lqtext/lqaddfile.c 1>&2
  947. sed 's/^X//' >lq-text/src/lqtext/lqaddfile.c <<'@@@End of lq-text/src/lqtext/lqaddfile.c'
  948. X/* lqaddfile.c -- Copyright 1989, 1990 Liam R. Quin.  All Rights Reserved.
  949. X * This code is NOT in the public domain.
  950. X * See the file COPYRIGHT for full details.
  951. X */
  952. X
  953. X/* addfile -- add a file to the LQ-Text text retrieval index
  954. X * Liam Quin, August 1989 and later...
  955. X *
  956. X * $Id: lqaddfile.c,v 1.14 91/03/02 21:22:39 lee Rel1-10 $ 
  957. X */
  958. X
  959. Xstatic char *Version = "@(#) $Id: lqaddfile.c,v 1.14 91/03/02 21:22:39 lee Rel1-10 $";
  960. X
  961. X#ifdef SYSV
  962. Xextern int _filbuf(); /* used but not defined in stdio.h */
  963. X#endif
  964. X#include <stdio.h>
  965. X#include <malloc.h>
  966. X#include <ctype.h>
  967. X#include <sys/types.h>
  968. X#include <sys/stat.h>
  969. X#ifdef BSD
  970. X# include <strings.h>
  971. X#else
  972. X# include <string.h>
  973. X#endif
  974. X
  975. X#include "globals.h" /* defines and declarations for database filenames */
  976. X#include "fileinfo.h"
  977. X#include "wordinfo.h"
  978. X#include "wordrules.h"
  979. X#include "filter.h"
  980. X
  981. X#include "emalloc.h"
  982. X
  983. X#define enew(var, type) (var = (type *) emalloc(sizeof(type)))
  984. X
  985. X#ifdef SYSV
  986. X#define TOLOWER(ch) ch = tolower(ch)
  987. X#else
  988. X#define TOLOWER(ch) if (isupper(ch)) ch = tolower(ch)
  989. X#endif
  990. X
  991. Xvoid DestroyFileInfo(), SaveFileInfo(), AddStream(), AddFrom();
  992. Xextern lqWriteAccess(); /* Allow write access to the database */
  993. X/* Symbol Table Interface */
  994. Xextern void AddWord(), WriteCurrentMaxWID();
  995. Xextern void DumpCache(), cleanupdb();
  996. Xextern char *WordRoot();
  997. Xextern int TooCommon(), GetFilterType();
  998. Xint RealGetChar(), AddFile();
  999. X
  1000. X/** System calls and library routines used in this file: **/
  1001. X/** System calls: **/
  1002. Xextern void exit();
  1003. Xextern int stat();
  1004. X/** Library Functions: **/
  1005. Xextern int atoi();
  1006. X#ifndef tolower
  1007. X extern int tolower();
  1008. X#endif
  1009. Xextern void perror();
  1010. X/**/
  1011. X
  1012. Xchar *progname = "@(#) : addfile.c,v 1.1 89/08/28 20:16:05 lee Locked $";
  1013. Xstatic int UseLineNumbers = 0;
  1014. X
  1015. X/* FROM pblock.c */
  1016. Xextern int AsciiTrace; /* provide increasingly verbose info if not zero */
  1017. X
  1018. Xstatic int LastChar = 0;
  1019. Xstatic int _chForLee = 0;
  1020. X
  1021. X#define GetChar(F) \
  1022. X    ( LastChar ? \
  1023. X    (++BytesRead, (_chForLee = LastChar), (LastChar = 0), _chForLee) : \
  1024. X    ( (_chForLee = getc(FileInfo->Stream)) != '\'' || !InWord) ? \
  1025. X        (++BytesRead, _chForLee) : RealGetChar(F) )
  1026. X     
  1027. Xint
  1028. Xmain(argc, argv)
  1029. X    int argc;
  1030. X    char *argv[];
  1031. X{
  1032. X    extern char *strrchr();
  1033. X    extern int getopt(), cknatstr();
  1034. X    extern void SetDefaults();
  1035. X    extern char *optarg;
  1036. X    extern int optind;
  1037. X    extern int MaxWordsInCache; /* see wordtable.c */
  1038. X
  1039. X    int c;
  1040. X    int ErrorFlag = 0;
  1041. X    int DoNothing = 0;
  1042. X    char *InputFile = (char *) 0;
  1043. X
  1044. X#ifdef MALLOCTRACE
  1045. X    malloc_debug(2);
  1046. X#endif
  1047. X
  1048. X    progname = argv[0]; /* retain the full path at first */
  1049. X
  1050. X#ifdef M_MXFAST
  1051. X    (void) mallopt(M_MXFAST, sizeof(t_WordPlace));
  1052. X    /* may need to comment mallopt() out entirely for BSD -- use ifndef.
  1053. X     * seems to work under SunOS, though.
  1054. X     * When it works, it says "Allocate 100 or so chunks of this size at a
  1055. X     * time, and whenver I ask for this much or less, give me one of the
  1056. X     * chunks".  Clearly it had better not be too large, but it is a big
  1057. X     * win with a structure allocated for every occurrence of every word!
  1058. X     */
  1059. X#endif
  1060. X
  1061. X    SetDefaults(argc, argv);
  1062. X
  1063. X    while ((c = getopt(argc, argv, "w:f:xVZz:")) != -1) {
  1064. X    switch (c) {
  1065. X    case 'w':
  1066. X        if (!cknatstr(optarg)) {
  1067. X        fprintf(stderr,
  1068. X                "%s: -w must be given a number >= 0, not \"%s\"\n",
  1069. X                                progname, optarg);
  1070. X        fprintf(stderr, "\tuse %s -xv for further information\n");
  1071. X        exit(1);
  1072. X        }
  1073. X        MaxWordsInCache = atoi(optarg);
  1074. X        break;
  1075. X    case 'Z':
  1076. X    case 'z':
  1077. X        break; /* work done in SetDefault() */
  1078. X    case 'V':
  1079. X        fprintf(stderr, "%s: version: %s\n", progname, Version);
  1080. X        DoNothing = 1;
  1081. X        break;
  1082. X    case 'f':
  1083. X        if (InputFile) {
  1084. X        fprintf(stderr,
  1085. X"%s: only one -f option allowed; use -xv for explanation\n", progname);
  1086. X
  1087. X        exit(1);
  1088. X        }
  1089. X        InputFile = optarg;
  1090. X        break;
  1091. X    case 'x':
  1092. X        ErrorFlag = (-1);
  1093. X        break;
  1094. X    default:
  1095. X    case '?':
  1096. X        ErrorFlag = 1;
  1097. X    }
  1098. X    }
  1099. X
  1100. X    if ((progname = strrchr(progname, '/')) != (char *) NULL) {
  1101. X    ++progname; /* step over the last / */
  1102. X    } else {
  1103. X    progname = argv[0];
  1104. X    }
  1105. X
  1106. X    if (ErrorFlag > 0) {
  1107. X    fprintf(stderr, "use %s -x or %s -xv for an explanation.\n",
  1108. X                            progname, progname);
  1109. X    exit(1);
  1110. X    } else if (ErrorFlag < 0) { /* -x was used */
  1111. X    fprintf(stderr, "%s -- add files to an lq-text retrieval database\n",
  1112. X                                    progname);
  1113. X
  1114. X    fputs("Options are:\n\
  1115. X    -f file -- read the list of files to index from \"file\"\n\
  1116. X    -c file    -- cfile contains a list of common words to be ignored\n\
  1117. X    -d dir    -- use the lq-text database in the named directory\n\
  1118. X    -t N    -- set the trace level to N [default: N = 0]\n\
  1119. X    -V    -- print Version number and exit\n\
  1120. X    -v    -- be verbose (equivalent to -t 1)\n\
  1121. X    -w n    -- dump the word-cache every n words\n\
  1122. X    -x    -- print this eXplanation and exit\n\
  1123. X    --    -- all following arguments are file names\n\
  1124. X\n\
  1125. X", stderr);
  1126. X    if (AsciiTrace == 1) {
  1127. X        /* used -v or -t1 */
  1128. X    fprintf(stderr, "\n\
  1129. X    Any remaining arguments are taken to be file names.  The current\n\
  1130. XDOCPATH (%s) is searched for the files, and they are read and added\n\
  1131. Xto the index.  (If you use the -f option, you should not give filename\n\
  1132. Xarguments on the command line, although you can use \"-f -\" to read the\n\
  1133. Xlist of files from standard input, one per line.\n\
  1134. XSetting (with -w) the size of the cache may dramatically\n\
  1135. Ximprove performance.  Systems with memory larger than the data can try -w0.\n\
  1136. XSee lqtext(1) for more information.\n", DocPath);
  1137. X    }
  1138. X    exit(0);
  1139. X
  1140. X    }
  1141. X
  1142. X    if (DoNothing) {
  1143. X    if (optind < argc) {
  1144. X        fprintf(stderr, "%s: warning: %d extra argument%s ignored...\n",
  1145. X                progname, argc - optind,
  1146. X                argc - optind == 1 ? "" : "%s" );
  1147. X        fprintf(stderr, "Use %s -x for an explanation\n", progname);
  1148. X    }
  1149. X    exit(0);
  1150. X    }
  1151. X
  1152. X    lqWriteAccess();
  1153. X
  1154. X    if (InputFile) {
  1155. X    if (optind < argc) {
  1156. X        fprintf(stderr, "%s: -f: too many arguments; use -xv\n", progname);
  1157. X        exit(1);
  1158. X    }
  1159. X    AddFrom(InputFile);
  1160. X    } else for (; optind < argc; ++optind) {
  1161. X    if (AddFile(argv[optind]) < 0 && AsciiTrace >= 1) {
  1162. X        fprintf(stderr, "%s: warning: Problem adding file %s\n",
  1163. X            progname, argv[optind]);
  1164. X    }
  1165. X    }
  1166. X
  1167. X#ifndef MALLOCTRACE
  1168. X    DumpCache(0); /* the 0 means don't bother calling free() */
  1169. X#else
  1170. X    DumpCache(1); /* Free everthing so whatever is left is a memory leak */
  1171. X#endif
  1172. X
  1173. X    cleanupdb(); /* empty the dbm cache */
  1174. X    WriteCurrentMaxWID();
  1175. X
  1176. X#ifdef MALLOCTRACE
  1177. X    (void) fprintf(stderr, "%s: Malloctrace: checking...\n", progname);
  1178. X    malloc_verify();
  1179. X    (void) fprintf(stderr, "%s: Malloc Map\n", progname);
  1180. X    mallocmap();
  1181. X#endif
  1182. X
  1183. X    exit(0);
  1184. X    /*NOTREACHED*/
  1185. X    return 1; /* disaster if we get here -- it's just for lint! */
  1186. X}
  1187. X
  1188. Xvoid
  1189. XAddFrom(Name)
  1190. X    char *Name;
  1191. X{
  1192. X    char *GetLine();
  1193. X
  1194. X    FILE *fp;
  1195. X    char *Line;
  1196. X
  1197. X    if (Name[0] == '-' && Name[1] == '\0') {
  1198. X    fp = stdin;
  1199. X    } else {
  1200. X    fp = fopen(Name, "r");
  1201. X    }
  1202. X
  1203. X    if (fp == (FILE *) 0) {
  1204. X    extern int errno;
  1205. X    int e = errno;
  1206. X
  1207. X    fprintf(stderr, "%s: -f: can't open ", progname);
  1208. X    errno = e;
  1209. X    perror(Name);
  1210. X    exit(1);
  1211. X    }
  1212. X
  1213. X    while ((Line = GetLine(fp, Name)) != (char *) 0) {
  1214. X    if (AddFile(Line) < 0 && AsciiTrace >= 1) {
  1215. X        /* we already got one error message from AddFile() */
  1216. X        fprintf(stderr, "%s: warning: Problem adding file %s\n",
  1217. X            progname, Line);
  1218. X    }
  1219. X    }
  1220. X
  1221. X    if (fp != stdin) {
  1222. X    (void) fclose(fp);
  1223. X    }
  1224. X}
  1225. X
  1226. Xstatic int LineInFile = 0;
  1227. Xstatic FILE *LastFile = 0;
  1228. X
  1229. Xchar *
  1230. XGetLine(fp, Name)
  1231. X    FILE *fp;
  1232. X    char *Name;
  1233. X{
  1234. X    static char *Line = (char *) 0;
  1235. X    static int Length = 0;
  1236. X    int ch;
  1237. X    register char *p;
  1238. X
  1239. X    if (!Line) {
  1240. X    if (Length <= 10) Length = 30;
  1241. X    Line = emalloc(Length);
  1242. X    }
  1243. X
  1244. X    p = Line;
  1245. X
  1246. X    if (fp == LastFile) {
  1247. X    ++LineInFile;
  1248. X    } else {
  1249. X    LineInFile = 0; /* number lines from zero! */
  1250. X    LastFile = fp;
  1251. X    }
  1252. X
  1253. X    while ((ch = getc(fp)) != EOF) {
  1254. X    static int HaveWarned = 0;
  1255. X
  1256. X    if (isspace(ch)) {
  1257. X        if (p == Line) { /* ignore blank lines and leading blanks */
  1258. X        continue;
  1259. X        }
  1260. X        if (ch == '\n') {
  1261. X        if (p == (char *) 0) {
  1262. X            /* how could this ever happen?  do I need it? */
  1263. X            p = Line;
  1264. X            continue;
  1265. X        }
  1266. X        *p = '\0';
  1267. X        return Line;
  1268. X        }
  1269. X        if (AsciiTrace && !HaveWarned) {
  1270. X        fprintf(stderr,
  1271. X"%s: -f: Warning: spaces found in filenames read from \"%s\"\n",
  1272. X                                progname, Name);
  1273. X        HaveWarned = 1;
  1274. X        }
  1275. X    }
  1276. X
  1277. X    /* add the character to the string */
  1278. X    if (p - Line + 1 >= Length) {
  1279. X        int SaveWhere = p - Line;
  1280. X        Length += 30;
  1281. X        Line = erealloc(Line, Length);
  1282. X        p = &Line[SaveWhere];
  1283. X    }
  1284. X    *p++ = ch;
  1285. X    }
  1286. X
  1287. X    if (p && Line && p != Line) {
  1288. X    fprintf(stderr, "%s: -f: warning: no newline at the end of \"%s\"\n",
  1289. X                        progname, Name);
  1290. X    *p = '\0';
  1291. X    return Line;
  1292. X    }
  1293. X
  1294. X    return (char *) 0;
  1295. X}
  1296. X
  1297. Xextern int fclose(), pclose();
  1298. X
  1299. Xt_FileInfo *
  1300. XMakeFileInfo(Name)
  1301. X    char *Name;
  1302. X{
  1303. X#ifdef BSD
  1304. X    extern time_t time();
  1305. X#else
  1306. X    extern long time();
  1307. X#endif
  1308. X    extern t_FID Name2FID();
  1309. X    extern t_FileInfo *GetFileInfo();
  1310. X    extern t_FID GetNextFID();
  1311. X    FILE *MakeInput();
  1312. X    struct stat StatBuf;
  1313. X
  1314. X    t_FileInfo *FileInfo = 0;
  1315. X    t_FID FID;
  1316. X
  1317. X    if (!Name || !*Name) return (t_FileInfo *) 0; /* sanity */
  1318. X
  1319. X    if (stat(Name, &StatBuf) < 0) {
  1320. X#ifndef FindFile /* it is a macro these days... */
  1321. X    extern char *FindFile();
  1322. X#endif
  1323. X    extern int errno;
  1324. X
  1325. X    int e = errno;
  1326. X    char *doc;
  1327. X
  1328. X    if ((doc = FindFile(Name)) == (char *) 0) {
  1329. X        fprintf(stderr, "Can't index ");
  1330. X        errno = e; /* fprintf might well clobber errno! */
  1331. X        perror(Name);
  1332. X        return (t_FileInfo *) 0;
  1333. X    }
  1334. X
  1335. X    if (stat(doc, &StatBuf) < 0) {
  1336. X        e = errno;
  1337. X        fprintf(stderr, "Can't index ");
  1338. X        errno = e; /* fprintf might well clobber errno! */
  1339. X        perror(Name);
  1340. X        return (t_FileInfo *) 0;
  1341. X    }
  1342. X    Name = doc;
  1343. X    }
  1344. X
  1345. X    if (StatBuf.st_size == 0L) {
  1346. X    if (AsciiTrace) {
  1347. X        fprintf(stderr, "%s empty -- not indexed\n", Name);
  1348. X    }
  1349. X    return (t_FileInfo *) 0;
  1350. X    }
  1351. X    /* See if it's in the index already: */
  1352. X    if ((FID = Name2FID(Name)) != (t_FID) 0) {
  1353. X
  1354. X    if ((FileInfo = GetFileInfo(FID)) != (t_FileInfo *) 0) {
  1355. X        /* Check to see if the file hass changed since it was last
  1356. X         * indexed.  If it has, we should delete the old one from
  1357. X         * the database and give this one a new FID, but I have
  1358. X         * not done that yet -- that's /usr/local/lib/lqtextd or
  1359. X         * something, I suppose!
  1360. X         */
  1361. X        if (FileInfo->Date >= StatBuf.st_mtime) {
  1362. X        if (AsciiTrace) {
  1363. X            fprintf(stderr, "%s unchanged -- not indexed\n", Name);
  1364. X        }
  1365. X        DestroyFileInfo(FileInfo);
  1366. X        return (t_FileInfo *) 0;
  1367. X        }
  1368. X    }
  1369. X    } else {
  1370. X    FID = GetNextFID((long) StatBuf.st_size);
  1371. X    }
  1372. X
  1373. X    if (FileInfo == (t_FileInfo *) 0) {
  1374. X    /* Allocate Structure */
  1375. X    enew(FileInfo, t_FileInfo);
  1376. X
  1377. X    /* Although not always necessary, call emalloc here so that a
  1378. X     * FileInfo can always be deleted with DestroyFileInfo()
  1379. X     */
  1380. X    FileInfo->Name = emalloc((unsigned)(strlen(Name) + 1));
  1381. X    (void) strcpy(FileInfo->Name, Name);
  1382. X
  1383. X    /* Other bits to set: */
  1384. X
  1385. X    /* date */
  1386. X    FileInfo->Date = StatBuf.st_mtime;
  1387. X
  1388. X    /* file type */
  1389. X    if ((FileInfo->FilterType = GetFilterType(FileInfo, &StatBuf)) < 0) {
  1390. X        if (AsciiTrace) {
  1391. X        fprintf(stderr, "%s unknown file type -- not indexed\n", Name);
  1392. X        }
  1393. X        (void) efree(FileInfo->Name);
  1394. X        (void) efree((char *) FileInfo);
  1395. X        return (t_FileInfo *) 0;
  1396. X    }
  1397. X    }
  1398. X
  1399. X    FileInfo->FID = FID;
  1400. X    FileInfo->Date = (long) time((long *) 0); /* it's a time_t on BSD */
  1401. X
  1402. X    if ((FileInfo->Stream = MakeInput(FileInfo)) == (FILE *) 0) {
  1403. X    fprintf(stderr, "%s: couldn't open filter for %s -- not indexed\n",
  1404. X                            progname, FileInfo->Name);
  1405. X    (void) efree(FileInfo->Name);
  1406. X    (void) efree((char *) FileInfo);
  1407. X    return (t_FileInfo *) 0;
  1408. X    }
  1409. X
  1410. X    return FileInfo;
  1411. X}
  1412. X
  1413. Xvoid
  1414. XDestroyFileInfo(FileInfo)
  1415. X    t_FileInfo *FileInfo;
  1416. X{
  1417. X    if (FileInfo->Stream) {
  1418. X    if (FileInfo->FilterType >= 0 && FileInfo->FilterType < MaxFilterType){
  1419. X        (* FilterTable[FileInfo->FilterType].close)(FileInfo->Stream);
  1420. X    }
  1421. X    FileInfo->Stream = (FILE *) 0;
  1422. X    }
  1423. X    if (FileInfo->Name) (void) efree(FileInfo->Name);
  1424. X    (void) efree((char *) FileInfo);
  1425. X}
  1426. X
  1427. Xint
  1428. XAddFile(Name)
  1429. X    char *Name;
  1430. X{
  1431. X    t_FileInfo *FileInfo;
  1432. X
  1433. X    if (!Name || !*Name) return -1;
  1434. X    if ((FileInfo = MakeFileInfo(Name)) == (t_FileInfo *) 0) return -1;
  1435. X
  1436. X    AddStream(FileInfo);
  1437. X    SaveFileInfo(FileInfo);
  1438. X    DestroyFileInfo(FileInfo);
  1439. X
  1440. X    return 0;
  1441. X}
  1442. X
  1443. XFILE *
  1444. XMakeInput(FileInfo)
  1445. X    t_FileInfo *FileInfo;
  1446. X{
  1447. X    FILE *fp;
  1448. X    char *Buffer;
  1449. X    unsigned BufLen;
  1450. X    extern FILE *fopen(), *popen();
  1451. X
  1452. X#define FSTRING FilterTable[FileInfo->FilterType].String
  1453. X
  1454. X    if (FileInfo->FilterType > MaxFilterType) {
  1455. X    fprintf(stderr, "%s: Warning: filter type %d for %s too high (max %d)\n",
  1456. X        progname, FileInfo->FilterType, FileInfo->Name, MaxFilterType);
  1457. X    return (FILE *) 0;
  1458. X    }
  1459. X
  1460. X    if (FilterTable[FileInfo->FilterType].Type != FileInfo->FilterType) {
  1461. X    fprintf(stderr, "Fatal Filter table error, %d\n", FileInfo->FilterType);
  1462. X    exit(3);
  1463. X    }
  1464. X
  1465. X    if (FSTRING == (char *) 0) {
  1466. X    return fopen(FileInfo->Name, "r");
  1467. X    }
  1468. X
  1469. X    BufLen = strlen(FileInfo->Name) * 2 + 4 + strlen(FSTRING);
  1470. X    /* The +4 is to allow for an embedded " < " plus a \0;
  1471. X     * we append "< Name", but also expand %s to be the Name, hence
  1472. X     * the strlen * 2
  1473. X     */
  1474. X    Buffer = emalloc(BufLen);
  1475. X
  1476. X    (void) sprintf(Buffer, FSTRING, FileInfo->Name);
  1477. X    (void) strcat(Buffer, " < ");
  1478. X    (void) strcat(Buffer, FileInfo->Name);
  1479. X
  1480. X    fp = popen(Buffer, "r");
  1481. X    (void) efree(Buffer);
  1482. X    return fp;
  1483. X}
  1484. X
  1485. Xstatic long BytesRead = 0L;
  1486. Xstatic int InWord = 0;
  1487. X
  1488. X/* Character input */
  1489. X
  1490. X#ifdef __GNU__
  1491. Xinline
  1492. X#endif
  1493. Xint
  1494. XRealGetChar(FileInfo)
  1495. X    t_FileInfo *FileInfo;
  1496. X{
  1497. X    /* ASSERT: InWord && _chForLee == '\'' */
  1498. X    LastChar = getc(FileInfo->Stream);
  1499. X    if (WithinWord(LastChar) && LastChar != '\'') {
  1500. X    BytesRead++;
  1501. X    return '\'';
  1502. X    } else {
  1503. X    /* delete the single quote, as it was at the end of
  1504. X     * a word, not in the middle
  1505. X     */
  1506. X    BytesRead++;
  1507. X    return ' ';
  1508. X    }
  1509. X    /*NOTREACHED*/
  1510. X    /* exit(1); */
  1511. X}
  1512. X
  1513. Xt_WordInfo *
  1514. XReadWord(FileInfo)
  1515. X    t_FileInfo *FileInfo;
  1516. X{
  1517. X    /* use two static storage areas so we can be called twice in a row.
  1518. X     * This is necessary to implement the WPF_LASTINBLOCK flag.
  1519. X     */
  1520. X    static t_WordInfo This, That;
  1521. X    static int ThisOrThat = 0;
  1522. X    t_WordInfo *WordInfo;
  1523. X    static char Buffer[MaxWordLength + 1];
  1524. X    int ch;
  1525. X    register char *q = Buffer;
  1526. X    static int WordInBlock;
  1527. X    static t_FID LastFid = 0L;
  1528. X    static long LastPos = 0L;
  1529. X    static int SawCommon = 0;
  1530. X    static int SawLetters = 0;
  1531. X    static int BlockInFile = 0L;
  1532. X    static unsigned long LastBlock;
  1533. X    unsigned long Start;
  1534. X
  1535. X    WordInfo = (ThisOrThat ? &This : &That);
  1536. X
  1537. X    if (FileInfo->FID != LastFid) {
  1538. X    LastFid = FileInfo->FID;
  1539. X    WordInBlock = (-1); /* none, yet! */
  1540. X    LastPos = BlockInFile = LastBlock = 0L;
  1541. X    BytesRead = 0L;
  1542. X    SawCommon = SawLetters = 0;
  1543. X    if (AsciiTrace) {
  1544. X        fprintf(stderr, "Reading file \"%s\"", FileInfo->Name);
  1545. X    }
  1546. X    }
  1547. X
  1548. X    /* Skip non-word characters */
  1549. X    while ((ch = GetChar(FileInfo)) != EOF) {
  1550. X    if (StartsWord(ch)) break;
  1551. X    }
  1552. X
  1553. X    /* ASSERT: we have read at least one character */
  1554. X
  1555. X    if (ch == EOF) {
  1556. X    if (AsciiTrace) {
  1557. X        fprintf(stderr, "\n");
  1558. X    }
  1559. X    return (t_WordInfo *) 0;
  1560. X    }
  1561. X
  1562. X    Start = BytesRead - 1;
  1563. X
  1564. X    if (UseLineNumbers) {
  1565. X    BlockInFile = LineInFile;
  1566. X    } else {
  1567. X    BlockInFile = Start / FileBlockSize;
  1568. X    }
  1569. X
  1570. X    if (BlockInFile != LastBlock) {
  1571. X    LastBlock = BlockInFile;
  1572. X    if (AsciiTrace > 1) {
  1573. X        fprintf(stderr, ".");
  1574. X#ifdef sun
  1575. X        /* SunOS seems to line-buffer stderr! */
  1576. X        fflush(stderr);
  1577. X#endif
  1578. X    }
  1579. X    WordInBlock = (-1);
  1580. X    }
  1581. X
  1582. X    if (isupper(ch)) {
  1583. X    WordInfo->WordPlace.Flags = WPF_UPPERCASE;
  1584. X    ch = tolower(ch);
  1585. X    } else {
  1586. X    WordInfo->WordPlace.Flags = 0;
  1587. X    }
  1588. X
  1589. X    InWord = 1; /* For GetChar() */
  1590. X
  1591. X    do {
  1592. X    if (q - Buffer < MaxWordLength) {
  1593. X        *q++ = ch;
  1594. X    }
  1595. X    ch = GetChar(FileInfo);
  1596. X    TOLOWER(ch);
  1597. X    } while (WithinWord(ch) || EndsWord(ch));
  1598. X
  1599. X    *q = '\0';
  1600. X    InWord = 0;
  1601. X
  1602. X#ifdef __GNUC__
  1603. X    /* this is to get round a gcc bug... */
  1604. X    {
  1605. X    int i = q - Buffer;
  1606. X    WordInfo->Length = i;
  1607. X
  1608. X    if (i < MinWordLength) {
  1609. X        register char *p;
  1610. X
  1611. X        for (p = Buffer; p < q; p++) {
  1612. X        if (isalpha(*p)) {
  1613. X            SawLetters = 1;
  1614. X            break;
  1615. X        }
  1616. X        }
  1617. X        return ReadWord(FileInfo);
  1618. X    }
  1619. X    }
  1620. X#else
  1621. X    if ((WordInfo->Length = q - Buffer) < MinWordLength) {
  1622. X    register char *p;
  1623. X
  1624. X    for (p = Buffer; p < q; p++) {
  1625. X        if (isalpha(*p)) {
  1626. X        SawLetters = 1;
  1627. X        break;
  1628. X        }
  1629. X    }
  1630. X    return ReadWord(FileInfo);
  1631. X    }
  1632. X#endif
  1633. X
  1634. X    WordInfo->Word = Buffer;
  1635. X
  1636. X    (void) WordRoot(WordInfo);
  1637. X
  1638. X    WordInfo->Length = strlen(WordInfo->Word);
  1639. X
  1640. X    if (TooCommon(WordInfo)) {
  1641. X    SawCommon++;
  1642. X    WordInBlock++;
  1643. X#ifdef ASCIITRACE
  1644. X    if (AsciiTrace > 10) {
  1645. X        fprintf(stderr, "%s too common to index\n", WordInfo->Word);
  1646. X    }
  1647. X#endif
  1648. X    return ReadWord(FileInfo);
  1649. X    } else if (SawCommon) {
  1650. X    SawCommon = 0;
  1651. X    WordInfo->WordPlace.Flags |= (WPF_LASTWASCOMMON|WPF_LASTHADLETTERS);
  1652. X    }
  1653. X    if (SawLetters) {
  1654. X    SawLetters = 0;
  1655. X    WordInfo->WordPlace.Flags |= WPF_LASTHADLETTERS;
  1656. X    }
  1657. X
  1658. X    /* StuffBefore is the # of chars between the end of the last word and
  1659. X     * the start of this one.
  1660. X     */
  1661. X    if (Start > 1L) {
  1662. X    if (Start - (LastPos + 1) <= 0) {
  1663. X        WordInfo->WordPlace.StuffBefore = 1; /* save a byte in the index */
  1664. X    } else if (Start - (LastPos + 1) >= 255 ) {
  1665. X        WordInfo->WordPlace.StuffBefore = 255;
  1666. X    } else {
  1667. X        WordInfo->WordPlace.StuffBefore = Start - (LastPos + 1);
  1668. X    }
  1669. X    } else {
  1670. X    WordInfo->WordPlace.StuffBefore = 1; /* i.e., the default */
  1671. X    }
  1672. X
  1673. X    WordInfo->WordPlace.FID = WordInfo->FID = FileInfo->FID;
  1674. X    WordInfo->WID = (t_WID) 0;
  1675. X    WordInfo->Next = (t_WordInfo *) 0;
  1676. X    WordInfo->WordPlaces = (t_WordPlace *) 0;
  1677. X    WordInfo->WordPlacesInHere = 0;
  1678. X    WordInfo->WordPlace.WordInBlock = (++WordInBlock);
  1679. X    WordInfo->WordPlace.BlockInFile = BlockInFile;
  1680. X    WordInfo->DataBlock = (char *) 0;
  1681. X
  1682. X    WordInfo->Word[WordInfo->Length] = '\0';
  1683. X
  1684. X    {
  1685. X    /* I want to avoid using malloc() here... 
  1686. X     * Another kludge would be to malloc sizeof(t_WordInfo) +
  1687. X     * strlen(WordInfo->Word + 1) and to put the string at the end
  1688. X     * of (i.e. just after) the struct.
  1689. X     */
  1690. X    static char Word2[MaxWordLength + 1];
  1691. X    static char Word1[MaxWordLength + 1];
  1692. X    char *p = (ThisOrThat) ? Word1 : Word2;
  1693. X
  1694. X    (void) strncpy(p, WordInfo->Word, (int) WordInfo->Length);
  1695. X    WordInfo->Word = p;
  1696. X    WordInfo->Word[WordInfo->Length] = '\0';
  1697. X    }
  1698. X
  1699. X    LastPos = BytesRead - 1;
  1700. X
  1701. X    ThisOrThat = !ThisOrThat;
  1702. X    /* toggle between 0 and 1.  Boring life, really */
  1703. X
  1704. X    if (!WordInfo->Word[0]) {
  1705. X    fprintf(stderr, "Null word in ReadWord()\n");
  1706. X    }
  1707. X    return WordInfo;
  1708. X}
  1709. X
  1710. Xvoid
  1711. XAddStream(FileInfo)
  1712. X    t_FileInfo *FileInfo;
  1713. X{
  1714. X    /* I have to mark the last word in the block.
  1715. X     * I do that by marking the previous word if it was in a differant block
  1716. X     * than the current one.
  1717. X     */
  1718. X    t_WordInfo *WordInfo;
  1719. X    t_WordInfo *LastWord = 0;
  1720. X
  1721. X    BytesRead = 0;
  1722. X
  1723. X    while ((WordInfo = ReadWord(FileInfo)) != (t_WordInfo *) 0) {
  1724. X    if (LastWord) {
  1725. X        if (LastWord->WordPlace.BlockInFile !=
  1726. X                        WordInfo->WordPlace.BlockInFile) {
  1727. X        LastWord->WordPlace.Flags |= WPF_LASTINBLOCK;
  1728. X        }
  1729. X        AddWord(LastWord);
  1730. X    }
  1731. X    LastWord = WordInfo;
  1732. X    }
  1733. X    if (LastWord) {
  1734. X    /* it's the last in the file, so it is also the last in the block */
  1735. X    LastWord->WordPlace.Flags |= WPF_LASTINBLOCK;
  1736. X    AddWord(LastWord);
  1737. X    }
  1738. X
  1739. X    if (AsciiTrace) {
  1740. X    fprintf(stderr, "Read %lu bytes from \"%s\"\n", BytesRead, FileInfo->Name);
  1741. X    }
  1742. X}
  1743. X
  1744. X/* lqaddfile has been carried through several incarnations of lq-text,
  1745. X * and hence has more than one Inital Revision in the following history.
  1746. X *
  1747. X * $Log:    lqaddfile.c,v $
  1748. X * Revision 1.14  91/03/02  21:22:39  lee
  1749. X * Added write access call.
  1750. X * 
  1751. X * Revision 1.13  91/03/02  18:53:25  lee
  1752. X * Common words are now counted, so you can now edit the common word list
  1753. X * without invalidating the index.
  1754. X * 
  1755. X * Revision 1.12  90/10/06  00:50:54  lee
  1756. X * Prepared for first beta release.
  1757. X * 
  1758. X * Revision 1.11  90/10/05  23:46:11  lee
  1759. X * Allow compilation with -UASCIITRACE
  1760. X * 
  1761. X * Revision 1.10  90/10/04  17:54:46  lee
  1762. X * fixed a typo in the usage message.
  1763. X * 
  1764. X * Revision 1.9  90/09/28  23:20:22  lee
  1765. X * Put more of GetChar into a macro and parameterised TOLOWER.
  1766. X * 
  1767. X * Revision 1.8  90/09/28  22:19:04  lee
  1768. X * Did the previous fix _properly_!
  1769. X * 
  1770. X * Revision 1.7  90/09/28  22:12:35  lee
  1771. X * Made getchar a macro, and deleted the call to CallFree...
  1772. X * 
  1773. X * Revision 1.6  90/09/20  18:46:03  lee
  1774. X * Closed up a (very small) memory leak.
  1775. X * 
  1776. X * Revision 1.5  90/09/19  20:16:41  lee
  1777. X * Fixed problems associated with indexing an empty file.
  1778. X * 
  1779. X * Revision 1.4  90/08/29  21:45:18  lee
  1780. X * Alpha release
  1781. X * 
  1782. X * Revision 1.3  90/08/09  19:17:12  lee
  1783. X * *** empty log message ***
  1784. X * 
  1785. X * Revision 1.1  90/02/27  11:05:02  lee
  1786. X * Initial revision
  1787. X * 
  1788. X * Revision 2.2  89/10/08  20:45:13  lee
  1789. X * Working version of nx-text engine.  Addfile and wordinfo work OK.
  1790. X * 
  1791. X * Revision 2.1  89/10/02  01:14:12  lee
  1792. X * New index format, with Block/WordInBlock/Flags/BytesSkipped info.
  1793. X * 
  1794. X * Revision 1.3  89/09/17  23:02:42  lee
  1795. X * Various fixes; NumberInBlock now a short...
  1796. X * 
  1797. X * Revision 1.2  89/09/16  21:16:11  lee
  1798. X * First demonstratable version.
  1799. X * 
  1800. X * Revision 1.1  89/09/07  21:05:52  lee
  1801. X * Initial revision
  1802. X *
  1803. X */
  1804. @@@End of lq-text/src/lqtext/lqaddfile.c
  1805. echo end of part 06
  1806. -- 
  1807. Liam R. E. Quin,  lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337
  1808.