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

  1. From: lee@sq.sq.com (Liam R. E. Quin)
  2. Newsgroups: alt.sources
  3. Subject: lq-text Full Text Retrieval Database Part 07/13
  4. Message-ID: <1991Mar4.020613.16578@sq.sq.com>
  5. Date: 4 Mar 91 02:06:13 GMT
  6.  
  7. : cut here --- cut here --
  8. : To unbundle, sh this file
  9. #! /bin/sh
  10. : part 07
  11. echo x - lq-text/src/lqtext/lqkwik.c 1>&2
  12. sed 's/^X//' >lq-text/src/lqtext/lqkwik.c <<'@@@End of lq-text/src/lqtext/lqkwik.c'
  13. X/* lqkwik.c -- Copyright 1991 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 */
  17. X
  18. X/* lqkwik -- produce a keyword-in-context list of matches...
  19. X * Liam R. Quin, February 1991 and later...
  20. X *
  21. X * $Id: lqkwik.c,v 1.1 91/03/02 20:37:47 lee Rel1-10 $
  22. X */
  23. X
  24. X#define COLS 65   /* the width of kwik    word index */
  25. X#define WORDCOL 25 /* where to put the    word in the index */
  26. X#define GAPWIDTH 2 /* space before the    word itself */
  27. X#define SCREENWIDTH 79
  28. X
  29. Xint Cols = COLS;
  30. Xint WordCol = WORDCOL;
  31. Xint GapWidth = GAPWIDTH;
  32. Xint ScreenWidth = SCREENWIDTH;
  33. X
  34. Xstatic int LinesAbove = 5;
  35. Xstatic int linesBelow = 5;
  36. X
  37. X#include "globals.h" /* defines and declarations for database filenames */
  38. X
  39. X#include <malloc.h>
  40. X#include <fcntl.h>
  41. X#include <ctype.h>
  42. X#include <sys/types.h> /* for fileinfo.h */
  43. X#include <sys/stat.h>
  44. X
  45. X#include <stdio.h>
  46. X
  47. X#include "fileinfo.h"
  48. X#include "wordinfo.h"
  49. X#include "wordrules.h"
  50. X#include "pblock.h"
  51. X#include "emalloc.h"
  52. X
  53. X/** Unix system calls that need declaring: **/
  54. Xextern long lseek();
  55. Xextern int open(), close();
  56. Xextern int read();
  57. Xextern void exit();
  58. Xextern int stat();
  59. X
  60. X/** Unix/C Library Functions that need declaring: **/
  61. X#ifndef tolower
  62. X extern int tolower();
  63. X#endif
  64. Xextern int strlen();
  65. Xextern int strcmp();
  66. Xextern unsigned sleep();
  67. Xextern int atoi();
  68. Xextern long atol();
  69. Xextern void perror();
  70. X
  71. X/** lqtext library functions that need declaring: **/
  72. Xextern int MySystem();
  73. Xextern int TooCommon();
  74. Xextern void SetDefault();
  75. Xextern void DefaultUsage();
  76. X
  77. X/** Functions within this file that are used before being defined: **/
  78. Xint ReadMatchFile();
  79. Xint ShowFile();
  80. Xvoid Output();
  81. X
  82. X/** **/
  83. X
  84. X/** some useful macros: **/
  85. X#define max(choir,boy) (((choir)>(boy))?(choir):(boy))
  86. X#define min(choir,boy) (((choir)<(boy))?(choir):(boy))
  87. X
  88. X/** **/
  89. X
  90. Xint AsciiTrace = 0;
  91. X
  92. Xextern int errno;
  93. X
  94. Xchar *progname = "lqkwik"; /* set from argv[] in main() */
  95. X
  96. Xint SelectedNames = -1;
  97. XFILE *InfoStream = 0;
  98. X
  99. Xstatic char *Revision = "@(#) showfile.c 2.2";
  100. X
  101. Xint
  102. Xmain(argc, argv)
  103. X    int argc;
  104. X    char *argv[];
  105. X{
  106. X    extern int optind, getopt();
  107. X    extern char *optarg; /* for getopt */
  108. X    int ch; /* for getopt */
  109. X    int ErrFlag = 0; /* see how getopt makes programs cleaner? */
  110. X    int NumberOfFiles;
  111. X    char *FileWithMatches = (char *) 0;
  112. X    char **MatchList;
  113. X    int MatchCount = 0;
  114. X    int Origc;
  115. X    int Right = Cols - (WordCol + GapWidth);
  116. X    int Left = WordCol - GapWidth;
  117. X
  118. X    progname = argv[0];
  119. X
  120. X    SetDefaults(argc, argv);
  121. X
  122. X    /* All lq-text programs must call SetDefaults() before getopt, and
  123. X     * must then be prepared to ignore options z with arg and Z without.
  124. X     */
  125. X    while ((ch = getopt(argc, argv, "a:b:f:l:r:g:w:o:z:ZVvx")) != EOF) {
  126. X    switch (ch) {
  127. X    case 'z':
  128. X        break; /* done by SetDefaults(); */
  129. X    case 'V':
  130. X        fprintf(stderr, "%s version %s\n", progname, Revision);
  131. X        break;
  132. X    case 'v':
  133. X        AsciiTrace = 1;
  134. X        break;
  135. X    case 'f':
  136. X        FileWithMatches = optarg;
  137. X        break;
  138. X    case 'g':
  139. X        GapWidth = atoi(optarg);
  140. X        break;
  141. X    case 'l':
  142. X        Left = atoi(optarg);
  143. X        break;
  144. X    case 'r':
  145. X        Right = atoi(optarg);
  146. X        break;
  147. X    case 'w':
  148. X        ScreenWidth = atoi(optarg);
  149. X        break;
  150. X    case 'x':
  151. X        ErrFlag = (-1);
  152. X        break;
  153. X    case '?':
  154. X    default:
  155. X        ErrFlag = 1;
  156. X    }
  157. X    }
  158. X
  159. X    if (ErrFlag < 0) { /* -x or -xv was used */
  160. X    fprintf(stderr, "usage: %s [-xv] [options] [matches...]\n", progname);
  161. X    fprintf(stderr,
  162. X    "use %s -x, -xv or -xvv for more detailed explanations.\n", progname);
  163. X
  164. X    if (AsciiTrace) {
  165. X        DefaultUsage();
  166. X        fprintf(stderr, "\n\
  167. X    -f file -- \"file\" contains a list of matches, one per line\n");
  168. X        fprintf(stderr, "\
  169. X    -g n    -- set gap between text and matched phrase to n [%d]\n\
  170. X    -l n    -- display n characters to the left of each phrase [%d]\n\
  171. X    -r n    -- display r chars to the right of each phrase's start [%d]\n\
  172. X    -w n    -- truncate the line after n characters [default: %d]\n",
  173. X            GapWidth,
  174. X            Left,
  175. X            Right,
  176. X            ScreenWidth
  177. X        );
  178. X    }
  179. X    if (AsciiTrace > 1) {
  180. X        fputs("\
  181. X    Matches should be in the form of\n\
  182. X        BlockNumber  WordInBlock  FileName\n\
  183. X    where BlockBumber and WordInBlock are positive numbers.\n\
  184. X    (This is the format produced by the lqword -l command.)\n\
  185. X", stderr);
  186. X    }
  187. X    exit(0);
  188. X    } else if (ErrFlag > 0) {
  189. X    fprintf(stderr, "use %s -x for an explanation.\n", progname);
  190. X    exit(1);
  191. X    }
  192. X
  193. X    Cols = Left + Right + GapWidth;
  194. X    WordCol = Left + GapWidth;
  195. X
  196. X    if (AsciiTrace) {
  197. X    fprintf(stderr,"Left:%d  Right:%d  Cols:%d  Gap:%d  WC:%d  SW:%d\n",
  198. X            Left, Right,      Cols, GapWidth, WordCol,ScreenWidth);
  199. X    }
  200. X
  201. X    if (ScreenWidth <= Cols + 2) {
  202. X    fprintf(stderr,
  203. X        "%s: ScreenWidth %d, %d text cols -- no room for file names!\n",
  204. X        progname, ScreenWidth, Cols);
  205. X    exit(1);
  206. X    }
  207. X
  208. X    /* open the file for the selected output */
  209. X    if (SelectedNames > 0) {
  210. X    if ((InfoStream = fdopen(SelectedNames, "w")) == (FILE *) 0) {
  211. X        int e = errno;
  212. X
  213. X        fprintf(stderr, "%s: -o %d: can't open stream ",
  214. X                            progname, SelectedNames);
  215. X        errno = e;
  216. X        perror("for writing");
  217. X        exit(1);
  218. X    }
  219. X    }
  220. X
  221. X    /* check that we can get at the file containing the matches, if one
  222. X     * was supplied.
  223. X     */
  224. X    if (FileWithMatches) {
  225. X    struct stat StatBuf;
  226. X    char *msg = 0;
  227. X
  228. X    if (stat(FileWithMatches, &StatBuf) < 0) {
  229. X        int e = errno; /* on many systems, fprintf() changes errno! */
  230. X        fprintf(stderr, "%s: can't open match-list file ", FileWithMatches);
  231. X        errno = e;
  232. X        perror(progname);
  233. X        exit(1);
  234. X    } else if (AsciiTrace) {
  235. X        switch (StatBuf.st_mode & S_IFMT) {
  236. X        case S_IFDIR:
  237. X        fprintf(stderr,
  238. X        "%s: ca't read matches from \"%s\" -- it's a directory!\n",
  239. X                        progname, FileWithMatches);
  240. X        exit(1);
  241. X        case S_IFREG:
  242. X        break;
  243. X#ifdef S_IFIFO
  244. X        case S_IFIFO:
  245. X        msg = "named pipe or fifo";
  246. X        /* fall through */
  247. X#endif
  248. X        case S_IFCHR:
  249. X        if (!msg) msg = "raw special device";
  250. X        /* fall through */
  251. X        case S_IFBLK:
  252. X        if (!msg) msg = "block special device";
  253. X        /* fall through */
  254. X#ifdef S_IFNAM
  255. X        case S_IFNAM:
  256. X        if (!msg) msg = "named special file"; /* wot dat? */
  257. X        /* fall through */
  258. X#endif
  259. X        default:
  260. X        if (!msg) msg = "special file";
  261. X
  262. X        fprintf(stderr,
  263. X            "%s: warning: file \"%s\" containing matches is a %s\n",
  264. X            progname, FileWithMatches, msg);
  265. X        
  266. X        /* but continue anyway... */
  267. X
  268. X        }
  269. X    }
  270. X    /* Now read the file, and make an array of matches... */
  271. X    if (ReadMatchFile(FileWithMatches, StatBuf.st_size, &MatchCount, &MatchList) < 0) {
  272. X        fprintf(stderr, "%s: couldn't read matches from \"%s\"\n",
  273. X                        progname, FileWithMatches);
  274. X        exit(1);
  275. X    }
  276. X    }
  277. X
  278. X    argv += optind;
  279. X    argc -= optind;
  280. X
  281. X    if (MatchCount) {
  282. X    argc = MatchCount;
  283. X    argv = MatchList;
  284. X    }
  285. X
  286. X    if (argc < 3) {
  287. X    fprintf(stderr,
  288. X    "%s: matches must have at least 3 parts; use -xv for an explanation\n",
  289. X                                progname);
  290. X    exit(1);
  291. X    } else if (argc % 3) {
  292. X    /* Note: I could detect lqword output here (i.e., without -l) */
  293. X    fprintf(stderr, "%s: can't understand match format;\n", progname);
  294. X    fprintf(stderr, "%s: use -xv for more explanation.\n", progname);
  295. X    exit(1);
  296. X    }
  297. X
  298. X    Origc = argc;
  299. X
  300. X    NumberOfFiles = argc / 3;
  301. X
  302. X    while (argc > 0) {
  303. X    int Where;
  304. X
  305. X    if (ShowFile(argv[2], atol(*argv), (unsigned) atoi(argv[1])) < 0) {
  306. X        int i;
  307. X
  308. X        /* This avoids repeated messages about the same file */
  309. X        for (i = argc - 3; i > 0; i -= 3) {
  310. X        if (STREQ(argv[2], argv[2 + 3])) {
  311. X            argv += 3;
  312. X        } else {
  313. X            break;
  314. X        }
  315. X        }
  316. X        argc = i + 3; /* so we can subtract 3 ... */
  317. X
  318. X    }
  319. X    argv += 3;
  320. X    argc -= 3;
  321. X    }
  322. X
  323. X    return 0;
  324. X}
  325. X
  326. Xint
  327. XReadMatchFile(FileWithMatches, FileSize, MatchCount, MatchList)
  328. X    char *FileWithMatches;
  329. X    off_t FileSize;
  330. X    int *MatchCount;
  331. X    char ** *MatchList;
  332. X{
  333. X    extern char *strtok();
  334. X
  335. X    int fd;
  336. X    char **Result;
  337. X    char *StorageArea;
  338. X    char *p;
  339. X    unsigned int n_matches;
  340. X    int BytesRead;
  341. X    int i;
  342. X    char *NextStr;
  343. X
  344. X    if (!FileWithMatches || !*FileWithMatches) {
  345. X    fprintf(stderr, "%s: match-list file (from -f) has empty name!\n",
  346. X                                progname);
  347. X    exit(1);
  348. X    }
  349. X
  350. X    if ((fd = open(FileWithMatches, O_RDONLY)) == 0) {
  351. X    int e = errno;
  352. X    fprintf(stderr, "%s: can't open match-list file ", progname);
  353. X    errno = e;
  354. X    perror(FileWithMatches);
  355. X    exit(1);
  356. X    }
  357. X
  358. X    /* We know the number of bytes, and each space or newline will get
  359. X     * turned into a null, so here goes...
  360. X     * The +1 below is to ensure that there is space for a \0, even if a
  361. X     * pesky user didn't put a \n at * the end of the file...
  362. X     * Sometimes I hate emacs...
  363. X     */
  364. X    if ((StorageArea = malloc((unsigned) FileSize + 1)) == (char *) 0) {
  365. X    fprintf(stderr, "%s: not enough memory to read match-list \"%s\"\n",
  366. X                            progname, FileWithMatches);
  367. X    exit(1);
  368. X    }
  369. X
  370. X    /* now read the list... */
  371. X    if ((BytesRead = read(fd, StorageArea, FileSize)) != FileSize) {
  372. X    if (BytesRead < 0) {
  373. X        int e = errno;
  374. X
  375. X        fprintf(stderr, "%s: couldn't read %u bytes from ",
  376. X                            progname, FileSize);
  377. X        errno = e;
  378. X        perror(FileWithMatches);
  379. X        exit(1);
  380. X    } else {
  381. X        int e = errno;
  382. X
  383. X        fprintf(stderr, "%s: ", progname);
  384. X        if (BytesRead > 4) { /* minimum plausible for 3 items */
  385. X        fprintf(stderr, "warning: ");
  386. X        }
  387. X        fprintf(stderr, "only read %u bytes, not %u, from file ",
  388. X                        progname, BytesRead, FileSize);
  389. X        errno = e;
  390. X        if (errno) perror(FileWithMatches);
  391. X        else fprintf(stderr, "\"%s\"\n", FileWithMatches);
  392. X
  393. X        if (BytesRead <= 4) exit(1);
  394. X
  395. X        StorageArea = realloc(StorageArea, (unsigned) (BytesRead + 1));
  396. X        if (StorageArea == (char *) 0) { /* unlikely, it got smaller  */
  397. X        fprintf(stderr, "%s: can't realloc for \"%s\"\n",
  398. X                        progname, FileWithMatches);
  399. X        exit(1);
  400. X        }
  401. X        FileSize = BytesRead;
  402. X    }
  403. X    }
  404. X
  405. X    /* null-terminate it */
  406. X    StorageArea[FileSize] = '\0';
  407. X
  408. X    /* got the data, now make an array... first, count the matches */
  409. X    for (n_matches = 1, p = StorageArea; p - StorageArea < FileSize; p++) {
  410. X    if isspace(*p) ++n_matches;
  411. X    }
  412. X
  413. X    /* If there *was* trailing new-line, we overestimated by one.
  414. X     * This doesn't matter.  If memory is that tight, initscr() will fail.
  415. X     * In any case, allow extra space for a trailing null entry.
  416. X     */
  417. X    ++n_matches;
  418. X    if (n_matches < 3) n_matches = 3;
  419. X
  420. X    Result = (char **) malloc((unsigned) n_matches * sizeof(char *));
  421. X    if (Result == (char **) 0) {
  422. X    fprintf(stderr, "%s: out of memory reading match file \"%s\"\n",
  423. X                        progname, FileWithMatches);
  424. X    exit(1);
  425. X    }
  426. X
  427. X    /* Now step through the Storage Area filling in the pointers to the args */
  428. X    ;
  429. X
  430. X    NextStr = (char *) 0;
  431. X    i = -1;
  432. X    for (p = StorageArea; p - StorageArea <= BytesRead; p++) {
  433. X    if (!NextStr) NextStr = p;
  434. X    if (isspace(*p) || p - StorageArea == BytesRead) {
  435. X        if (p - StorageArea != BytesRead) *p = '\0';
  436. X        while (isspace(*p)) { /* eat multiple blanks */
  437. X        p++;
  438. X        }
  439. X        if (++i >= n_matches) {
  440. X        n_matches += 20;
  441. X        if ((Result = (char **)
  442. X            realloc((char *) Result, n_matches * sizeof(char *))) ==
  443. X                                (char **) 0) {
  444. X            fprintf(stderr,
  445. X            "%s: out of memory [%u] in match-file \"%s\"\n",
  446. X            progname, n_matches * sizeof(char *), FileWithMatches);
  447. X            /* TODO -- return with fewer matches -- NOTDONE */
  448. X            exit(1);
  449. X        }
  450. X        }
  451. X        *p = '\0'; /* OK at the very end cos of the extra byte! */
  452. X        Result[i] = NextStr;
  453. X        NextStr = (char *) 0;
  454. X    }
  455. X    }
  456. X
  457. X    if (i + 2 < n_matches) {
  458. X    Result = (char **) realloc((char *)Result,
  459. X                    (unsigned) (i+2) * sizeof(char **));
  460. X    if (Result == (char **) 0) {
  461. X        fprintf(stderr, "%s: no memory for match-list from \"%s\"\n",
  462. X                        progname, FileWithMatches);
  463. X        exit(1);
  464. X    }
  465. X    }
  466. X
  467. X    if (close(fd) < 0) {
  468. X    fprintf(stderr, "%s: warning: obscure problem closing %d (\"%s\")\n",
  469. X                        progname, fd, FileWithMatches);
  470. X    sleep(5);
  471. X    }
  472. X
  473. X    (*MatchList) = Result;
  474. X    return (*MatchCount = i);
  475. X}
  476. X
  477. Xint
  478. XShowFile(FileName, BlockInFile, WordInBlock)
  479. X    char *FileName;
  480. X    unsigned long BlockInFile;
  481. X    unsigned int WordInBlock;
  482. X{
  483. X    static char *Buffer = 0;
  484. X    int fd;
  485. X    static unsigned int BufLen;
  486. X    int AmountRead;
  487. X    register char *p;
  488. X    register char *q;
  489. X    int InTargetWord = 0;
  490. X    char *StartOfMyWord;
  491. X    int ThisWord = 0;
  492. X    char *Start;
  493. X    char *ThisLine = emalloc(Cols + 1); /* +1 for trailing \0 */
  494. X    char *FirstBit = emalloc(WordCol - GapWidth + 1); /* +1 for trailing \0 */
  495. X    char *LastBit = emalloc(Cols - WordCol + 1); /* +1 for trailing \0 */
  496. X    char *FirstStart;
  497. X
  498. X    if (Buffer == (char *) 0) {
  499. X    BufLen = Cols * 10;
  500. X    if (BufLen < FileBlockSize * 3) BufLen = FileBlockSize * 3;
  501. X    Buffer = emalloc(BufLen);
  502. X    }
  503. X
  504. X    errno = 0;
  505. X
  506. X    if ((fd = open(FileName, O_RDONLY, 0)) < 0) {
  507. X    int e = errno;
  508. X    char *doc;
  509. X
  510. X    if ((doc = FindFile(FileName)) == (char *) 0) {
  511. X        fprintf(stderr, "%s: %s: ", progname, FileName);
  512. X        errno = e;
  513. X        perror(FileName);
  514. X        efree(ThisLine); efree(FirstBit); efree(LastBit);
  515. X        return -1;
  516. X    } else if ((fd = open(doc, O_RDONLY, 0)) < 0) {
  517. X        fprintf(stderr, "%s: %s: ", progname, FileName);
  518. X        errno = e;
  519. X        perror(doc);
  520. X        efree(ThisLine); efree(FirstBit); efree(LastBit);
  521. X        return -1;
  522. X    }
  523. X    FileName = doc;
  524. X    }
  525. X
  526. X    errno = 0;
  527. X    if (lseek(fd, BlockInFile? (long) ((BlockInFile - 1) * FileBlockSize) : 0L,
  528. X                                    0) < 0) {
  529. X    int e = errno;
  530. X    fprintf(stderr, "%s: %s: ", progname, FileName);
  531. X    errno = e;
  532. X    perror("lseek");
  533. X    efree(ThisLine); efree(FirstBit); efree(LastBit);
  534. X    return;
  535. X    }
  536. X
  537. X    errno = 0;
  538. X    if ((AmountRead = read(fd, Buffer, BufLen)) < MinWordLength) {
  539. X    int e = errno;
  540. X    fprintf(stderr, "%s: %s: ", progname, FileName);
  541. X    errno = e;
  542. X    perror("read");
  543. X    efree(ThisLine); efree(FirstBit); efree(LastBit);
  544. X    return -1;
  545. X    }
  546. X
  547. X
  548. X    /** Find the required word */
  549. X    if (BlockInFile) {
  550. X    /* start 1 char before the end of the previous block */
  551. X    StartOfMyWord = &Buffer[FileBlockSize - 1];
  552. X    /* perhaps the last word of the previous block spans the block
  553. X     * boundary?
  554. X     */
  555. X    while (WithinWord(*StartOfMyWord)) StartOfMyWord++;
  556. X    if (StartOfMyWord < &Buffer[FileBlockSize]) {
  557. X        StartOfMyWord = &Buffer[FileBlockSize];
  558. X    }
  559. X    } else {
  560. X    StartOfMyWord = Buffer;
  561. X    }
  562. X
  563. X    (void) close(fd);
  564. X
  565. X    for (ThisWord = 0; ThisWord <= WordInBlock + 1; ThisWord++) {
  566. Xbored:
  567. X    /* skip to the start of a word */
  568. X    while (!StartsWord(*StartOfMyWord)) {
  569. X        ++StartOfMyWord;
  570. X    }
  571. X
  572. X    Start = StartOfMyWord;
  573. X
  574. X    /* find the end of the word */
  575. X    while (WithinWord(*StartOfMyWord)) {
  576. X        if (*StartOfMyWord == '\'' && !EndsWord(StartOfMyWord[1])) break;
  577. X        StartOfMyWord++;
  578. X    }
  579. X
  580. X    /* Assert: StartOfMyWord points 1 character beyond the end of the
  581. X     * word pointed to by Start
  582. X     */
  583. X    /* see if it's long enough */
  584. X    if (StartOfMyWord - Start < MinWordLength) {
  585. X        goto bored;
  586. X    }
  587. X
  588. X    /** See if it's the right one */
  589. X    if (ThisWord == WordInBlock) {
  590. X        StartOfMyWord = Start;
  591. X        break;
  592. X    }
  593. X    }
  594. X
  595. X
  596. X    /* Find context before the keyword */
  597. X
  598. X    q = &FirstBit[WordCol - GapWidth];
  599. X    *q-- = '\0';
  600. X
  601. X    for (p = StartOfMyWord - 1; p >= Buffer; --p, --q) {
  602. X    *q = (isspace(*p)) ? ' ' : *p;
  603. X    if (q == FirstBit) break;
  604. X    }
  605. X
  606. X    FirstStart = q;
  607. X
  608. X    /* now build up the rest of the buffer */
  609. X
  610. X    q = LastBit;
  611. X    *q = '\0';
  612. X
  613. X    InTargetWord = 0;
  614. X
  615. X    for (p = StartOfMyWord; p - Buffer < AmountRead; p++) {
  616. X    if (q >= &LastBit[Cols - WordCol]) break;
  617. X
  618. X    switch (InTargetWord) {
  619. X    case 0:
  620. X        if (StartsWord(*p)) {
  621. X        InTargetWord = 1;
  622. X        }
  623. X        break;
  624. X    case 1:
  625. X        if (!WithinWord(*p)) {
  626. X        InTargetWord = 2;
  627. X        }
  628. X    }
  629. X    if (isspace(*p)) {
  630. X        *q = ' ';
  631. X    } else {
  632. X        *q = *p;
  633. X    }
  634. X    *++q = '\0';
  635. X    if (q >= &LastBit[Cols - WordCol]) break;
  636. X    }
  637. X
  638. X    printf("%*.*s", WordCol - GapWidth, WordCol - GapWidth, FirstStart);
  639. X
  640. X    /* do the gap */
  641. X    {
  642. X
  643. X    register int i;
  644. X
  645. X    for (i = GapWidth; i > 0; i--) {
  646. X        putchar(' ');
  647. X    }
  648. X    }
  649. X
  650. X    printf("%-*.*s", Cols - WordCol, Cols - WordCol, LastBit);
  651. X    
  652. X    printf(":");
  653. X    {
  654. X    int OverShoot = Cols + 2 + strlen(FileName) - ScreenWidth; /* +2 is ": " */
  655. X
  656. X    if (OverShoot > 0) {
  657. X        FileName += OverShoot + 2;
  658. X        printf("...");
  659. X    } else {
  660. X        putchar(' ');
  661. X    }
  662. X
  663. X    }
  664. X    printf("%s\n", FileName);
  665. X
  666. X    efree(ThisLine); efree(FirstBit); efree(LastBit);
  667. X    return 0;
  668. X}
  669. X
  670. X
  671. X/*
  672. X * $Log:    lqkwik.c,v $
  673. X * Revision 1.1  91/03/02  20:37:47  lee
  674. X * Initial revision
  675. X * 
  676. X *
  677. X */
  678. @@@End of lq-text/src/lqtext/lqkwik.c
  679. echo x - lq-text/src/lqtext/lqphrase.c 1>&2
  680. sed 's/^X//' >lq-text/src/lqtext/lqphrase.c <<'@@@End of lq-text/src/lqtext/lqphrase.c'
  681. X/* lqphrase.c -- Copyright 1989, 1990 Liam R. Quin.  All Rights Reserved.
  682. X * This code is NOT in the public domain.
  683. X * See the file COPYRIGHT for full details.
  684. X *
  685. X * $Id: lqphrase.c,v 1.4 90/10/06 00:50:56 lee Rel1-10 $
  686. X */
  687. X
  688. X/* lqphrase, part of Liam Quin's text retrieval package...
  689. X *
  690. X * lqphrase is intended to be an example of one way to use the programming
  691. X * interface to lq-text.
  692. X *
  693. X * The idea is quite simple:
  694. X * Simply take a phrase p, held in a string (char *p), and call
  695. X *    t_Phrase *Phrase = String2Phrase(p);
  696. X * The result, if not null, contains only one interesting thing at this
  697. X * point:
  698. X *    Phrase->ModifiedString
  699. X * is the canonical version of p -- with common and short words removed.
  700. X * for example,
  701. X *    p = "The boy sat down in His Boat and playd with his toes.";
  702. X * might result in Phrase->ModifiedString containing
  703. X *    "[*the] boy sat down [in] [*his] boat [*and] [?playd] with [*his] toe"
  704. X * Common words are marked with a *, and unknown words with ?.
  705. X * An attempt may have been made to reduce plurals.
  706. X * Since this phrase contains a word not in the database (playd), it will
  707. X * never match anything.  As a result, it is a good idea to print this string
  708. X * (possibly massaging it first) so users can see what is going on.  If you
  709. X * have it, the curses-based "lqtext" does this.
  710. X *
  711. X * If we change "playd" to "played", the above string is equivalent to
  712. X *    "[*the] boy sat down [xx] [*the] boat [*the] played with [*the] toe"
  713. X * In other words, all common words are equivalent.  The package remembers
  714. X * that one or more common words were skipped, and also that one or more
  715. X * lumps of letters too small to make up a word were skipped.
  716. X * The following are equivalent:
  717. X * L.R.E. Quin    L. Quin    L.R.Quin    X.X.Quin
  718. X * in a QUIN    a QuIn
  719. X * and the following are not the same as those:
  720. X * Quin (no preceding garbage)
  721. X * L.R.E. quin (first letter of `Quin' is not upper case (the rest is ignored)
  722. X * [*the] Quin (common words are not the same as skipped letters)
  723. X * L. Quin's (the presence of the posessive ('s) is significant)
  724. X * L. Quins (plural (two Quins) not the same as singular)
  725. X * L. Quinn (spelt incorrectly!)
  726. X *
  727. X * Now, having sorted that out, we have our canonical string (and lots of
  728. X * other things) in Phrase, so we can now call
  729. X *    MakeMatches(Phrase);
  730. X * This will return the number of matches (*NOT* the number of files) for
  731. X * the given ModifiedPhrase in the database.
  732. X * This can take several seconds, so again, it can be worth printing out
  733. X * the modified string as soon as it is available, so the user is looking at
  734. X * that whilst MakeMatches is working!  I have experimented with faster
  735. X * versions of MakeMatches involving binary search, but the extra complexity
  736. X * slowed things down on smaller databases.  I don't have enough disk space
  737. X * here to make a large enough database to do real timings, sorry.
  738. X *
  739. X * Now we have done MakeMatches, we can marck along the linked list of
  740. X * pointers to linked lists of arrays of matches.  Clear?  No?  Well,
  741. X * that's why there's en axample.  See Match() below.
  742. X *
  743. X * Now, each match currently gives us
  744. X * t_FID FID; Files are numbered from 1 in the database
  745. X * unsigned long BlockInFile; -- the block in the file
  746. X * unsigned char WordInBlock; -- the word in the block
  747. X * unsigned char StuffBefore; -- the amount of leading garbage
  748. X * unsigned char Flags, including (see wordrules.h):
  749. X *
  750. X * WPF_WASPLURAL        The word...  ended in s
  751. X * WPF_UPPERCASE        ...Started with a capital letter
  752. X * WPF_POSSESSIVE        ...ended in 's
  753. X * WPF_ENDEDINING        ...ended in ing
  754. X * WPF_LASTWASCOMMON    the previous word was common
  755. X * WPF_LASTHADLETTERS    we skipped some letters to get here
  756. X * WPF_LASTINBLOCK    I'm the last word in this block
  757. X *
  758. X */
  759. X
  760. X#include "globals.h" /* defines and declarations for database filenames */
  761. X
  762. X#include <stdio.h> /* stderr, also for fileinfo.h */
  763. X#include <fcntl.h>
  764. X#include <sys/types.h>
  765. X#include <malloc.h>
  766. X#include "emalloc.h"
  767. X#include "fileinfo.h" /* for wordinfo.h */
  768. X#include "wordinfo.h"
  769. X#include "pblock.h"
  770. X#include "phrase.h"
  771. X
  772. X#ifndef STREQ
  773. X# define STREQ(boy,girl) ((*(boy) == *(girl)) && (!strcmp((boy),(girl))))
  774. X#endif
  775. X
  776. Xextern int AsciiTrace;
  777. Xextern t_PhraseCaseMatch PhraseMatchLevel;
  778. X
  779. X/** System calls and functions... **/
  780. X/** Unix system calls used in this file: **/
  781. Xextern void exit();
  782. X
  783. X/** Unix Library Functions used: **/
  784. X/** lqtext library functions: **/
  785. Xextern void SetDefaults();
  786. Xextern void DefaultUsage();
  787. X
  788. X/** functions used before they're defined within this file: **/
  789. Xvoid Match();
  790. X/** **/
  791. X
  792. Xstatic char *Revision = "@(#) $Id: lqphrase.c,v 1.4 90/10/06 00:50:56 lee Rel1-10 $";
  793. X
  794. Xchar *progname = "tryphrase";
  795. X
  796. Xint SilentMode = 0; /* don't print matches if set to one */
  797. X
  798. Xint
  799. Xmain(argc, argv)
  800. X    int argc;
  801. X    char *argv[];
  802. X{
  803. X    extern int optind, getopt();
  804. X    /** extern char *optarg; (unused at present) **/
  805. X    int ch;
  806. X    int ErrorFlag = 0;
  807. X
  808. X    progname = argv[0];
  809. X
  810. X    SetDefaults(argc, argv);
  811. X
  812. X    while ((ch = getopt(argc, argv, "Zz:ahpslxVv")) != EOF) {
  813. X    switch (ch) {
  814. X    case 'z':
  815. X    case 'Z':
  816. X        break; /* done by SetDefaults(); */
  817. X    case 'V':
  818. X        fprintf(stderr, "%s version %s\n", progname, Revision);
  819. X        break;
  820. X    case 'v': /* same as -t 1 */
  821. X        AsciiTrace = 1;
  822. X        break;
  823. X    case 'l':
  824. X        break; /* list mode is the default */
  825. X    case 's':
  826. X        SilentMode = 1;
  827. X        break;
  828. X    case 'x':
  829. X        ErrorFlag = (-1);
  830. X        break;
  831. X    case '?':
  832. X        ErrorFlag = 1;
  833. X    }
  834. X    }
  835. X
  836. X    /* Normally put call to lrqError here to give a helpful message,
  837. X     * but not yet ready to ship the error handling package, sorry
  838. X     */
  839. X    if (ErrorFlag) {
  840. X    fprintf(stderr, "Usage: %s [options] \"phrase\" [...]\n", progname);
  841. X    fprintf(stderr, "%s: options are:\n", progname);
  842. X    fputs("\
  843. X    -l    -- list mode, suitable for lqshow (the default)\n\
  844. X    -s    -- silent mode; exit status indicates success of matching\n\
  845. X\n", stderr);
  846. X
  847. X    DefaultUsage();
  848. X    exit( ErrorFlag > 0 ? 1 : 0); /* 0 means -x was used */
  849. X    }
  850. X    
  851. X    if (AsciiTrace > 1) {
  852. X    switch (PhraseMatchLevel) {
  853. X    case PCM_HalfCase:
  854. X        fprintf(stderr, "%s: Matching phrases heuristically.\n", progname);
  855. X        break;
  856. X    case PCM_SameCase:
  857. X        fprintf(stderr, "%s: Matching phrases precisely.\n", progname);
  858. X        break;
  859. X    case PCM_AnyCase:
  860. X        fprintf(stderr, "%s: Matching phrases approximately.\n", progname);
  861. X        break;
  862. X    default:
  863. X        fprintf(stderr, "%s: internall error, case matching is %d\n",
  864. X                        progname, PhraseMatchLevel);
  865. X        exit(2);
  866. X    }
  867. X    }
  868. X
  869. X    while (optind < argc) {
  870. X    Match(argv[optind++]);
  871. X    }
  872. X
  873. X    if (SilentMode) {
  874. X    /* if we got to here we didn't find anything */
  875. X    exit(1);
  876. X    }
  877. X    return 0;
  878. X}
  879. X
  880. Xvoid
  881. XMatch(Phrase)
  882. X    char *Phrase;
  883. X{
  884. X    extern t_Phrase *String2Phrase();
  885. X    extern t_FileInfo *GetFileInfo();
  886. X    extern long MakeMatches();
  887. X
  888. X    t_Phrase *P;
  889. X    t_MatchList *Matches;
  890. X    t_FID LastFID = (t_FID) 0;
  891. X    t_FileInfo *FileInfo = 0;
  892. X
  893. X    if (!Phrase || !*Phrase) return;
  894. X    if ((P = String2Phrase(Phrase)) == (t_Phrase *) 0) return;
  895. X
  896. X    if (MakeMatches(P) <= 0L) return;
  897. X
  898. X    if (P) {
  899. X    for (Matches = P->Matches; Matches != (t_MatchList *) 0;
  900. X                        Matches = Matches->Next) {
  901. X        if (Matches->Match != (t_Match *) 0) {
  902. X        if (Matches->Match->Where->FID != LastFID) {
  903. X            t_FID FID = Matches->Match->Where->FID;
  904. X            /*TODO: use DestroyFileInfo instead of efree:... */
  905. X            if (FileInfo) efree((char *) FileInfo);
  906. X            if ((FileInfo = GetFileInfo(FID)) == (t_FileInfo *) 0) {
  907. X            continue;
  908. X            }
  909. X            LastFID = FID;
  910. X        }
  911. X
  912. X        /* Now that we know that we have something to print... */
  913. X        if (SilentMode) {
  914. X            exit(0); /* OK, found something */
  915. X        }
  916. X        if (AsciiTrace) {
  917. X            printf("%-7lu %-7u %-3d %-3d %s\n",
  918. X                Matches->Match->Where->BlockInFile,
  919. X                (unsigned) Matches->Match->Where->WordInBlock,
  920. X                (unsigned) Matches->Match->Where->StuffBefore,
  921. X                (unsigned) Matches->Match->Where->Flags,
  922. X                FileInfo->Name);
  923. X        } else {
  924. X            printf("%-7.7lu %-7.7u %s\n",
  925. X                Matches->Match->Where->BlockInFile,
  926. X                Matches->Match->Where->WordInBlock,
  927. X                FileInfo->Name);
  928. X        }
  929. X        }
  930. X    }
  931. X    }
  932. X}
  933. X
  934. X/*
  935. X * $Log:    lqphrase.c,v $
  936. X * Revision 1.4  90/10/06  00:50:56  lee
  937. X * Prepared for first beta release.
  938. X * 
  939. X * Revision 1.3  90/08/29  21:45:29  lee
  940. X * Alpha release
  941. X * 
  942. X * Revision 1.2  90/08/09  19:17:16  lee
  943. X * *** empty log message ***
  944. X * 
  945. X * Revision 1.1  90/03/24  20:22:49  lee
  946. X * Initial revision
  947. X * 
  948. X */
  949. X
  950. @@@End of lq-text/src/lqtext/lqphrase.c
  951. echo x - lq-text/src/lqtext/lqshow.c 1>&2
  952. sed 's/^X//' >lq-text/src/lqtext/lqshow.c <<'@@@End of lq-text/src/lqtext/lqshow.c'
  953. X/* lqshow.c -- Copyright 1989, 1990 Liam R. Quin.  All Rights Reserved.
  954. X * This code is NOT in the public domain.
  955. X * See the file COPYRIGHT for full details.
  956. X */
  957. X
  958. X/* lqshow -- show a file according to keywords, highlighting matches
  959. X * Liam R. Quin, September 1989 and later...
  960. X *
  961. X * $Id: lqshow.c,v 1.9 91/03/03 00:18:26 lee Rel1-10 $
  962. X */
  963. X
  964. X#include "globals.h" /* defines and declarations for database filenames */
  965. X
  966. X#ifdef SYSV
  967. X /* for lint: */
  968. X extern int w32addch();
  969. X#endif
  970. X#ifdef ultrix
  971. X# include <cursesX.h>
  972. X#else
  973. X# include <curses.h>
  974. X#endif
  975. X#include <malloc.h>
  976. X#include <fcntl.h>
  977. X#include <ctype.h>
  978. X#include <sys/types.h> /* for fileinfo.h */
  979. X#include <sys/stat.h>
  980. X
  981. X/* Check for old (or BSD) curses: */
  982. X#ifndef A_STANDOUT
  983. X# define A_STANDOUT 10193 /* random */
  984. X# define A_UNDERLINE 312
  985. X# define attrset(a) ((a == 0) ? standend() : standout())
  986. Xtypedef char chtype; /* long on sysV */
  987. Xbeep() {
  988. X    fprintf(stderr, "\007");
  989. X    fflush(stderr);
  990. X}
  991. X#endif
  992. X
  993. X#include "fileinfo.h"
  994. X#include "wordinfo.h"
  995. X#include "wordrules.h"
  996. X#include "pblock.h"
  997. X#include "emalloc.h"
  998. X
  999. X/** Unix system calls that need declaring: **/
  1000. Xextern long lseek();
  1001. Xextern int open(), close();
  1002. Xextern int read();
  1003. Xextern void exit();
  1004. Xextern int stat();
  1005. X
  1006. X/** Unix/C Library Functions that need declaring: **/
  1007. X#ifndef tolower
  1008. X extern int tolower();
  1009. X#endif
  1010. Xextern int strlen();
  1011. Xextern int strcmp();
  1012. Xextern unsigned sleep();
  1013. Xextern int atoi();
  1014. Xextern long atol();
  1015. Xextern void perror();
  1016. X
  1017. X/** Curses library functions: **/
  1018. X#ifdef SYSV
  1019. Xextern int box32();
  1020. X#endif
  1021. X#ifndef nonl
  1022. X extern int nonl();
  1023. X#endif /**nonl*/
  1024. X#ifndef noecho
  1025. Xextern int noecho();
  1026. X#endif
  1027. X#ifndef wmove
  1028. X extern int wmove();
  1029. X#endif
  1030. X#ifndef waddstr
  1031. X extern int waddstr();
  1032. X#endif
  1033. X#ifndef wrefresh
  1034. X extern int wrefresh();
  1035. X#endif
  1036. X#ifndef beep
  1037. X extern int beep();
  1038. X#endif
  1039. X#ifndef wprintw
  1040. X extern int printw();
  1041. X#endif
  1042. Xextern int mvwprintw(), delwin(), wclear(), wclrtoeol(), endwin();
  1043. X
  1044. X/** lqtext library functions that need declaring: **/
  1045. Xextern int MySystem();
  1046. Xextern int TooCommon();
  1047. Xextern void SetDefault();
  1048. Xextern void DefaultUsage();
  1049. X
  1050. X/** Functions within this file that are used before being defined: **/
  1051. Xint ReadMatchFile();
  1052. Xvoid ShowFile();
  1053. Xvoid Output();
  1054. X
  1055. X/** **/
  1056. X
  1057. X/** some useful macros: **/
  1058. X#define max(choir,boy) (((choir)>(boy))?(choir):(boy))
  1059. X#define min(choir,boy) (((choir)<(boy))?(choir):(boy))
  1060. X
  1061. X/** **/
  1062. X
  1063. Xint AsciiTrace = 0;
  1064. X
  1065. X/* number of lines above and below each match to show by default. */
  1066. X#define DFLTABOVE 6
  1067. X#define DFLTBELOW 9
  1068. X
  1069. Xint LinesBelow = DFLTBELOW;
  1070. Xint LinesAbove = DFLTABOVE;
  1071. X
  1072. X#define DISPLAY_TOP 3
  1073. X
  1074. Xextern int errno;
  1075. X
  1076. Xchar *progname;
  1077. Xint ThisRow, ThisCol;
  1078. Xint SelectedNames = -1;
  1079. XFILE *InfoStream = 0;
  1080. X
  1081. Xstatic char *Revision = "@(#) showfile.c 2.2";
  1082. X
  1083. Xint
  1084. Xmain(argc, argv)
  1085. X    int argc;
  1086. X    char *argv[];
  1087. X{
  1088. X    extern int optind, getopt();
  1089. X    extern char *optarg; /* for getopt */
  1090. X    int ch; /* for getopt */
  1091. X    int ErrFlag = 0; /* see how getopt makes programs cleaner? */
  1092. X    int NumberOfFiles;
  1093. X    char **Origv;
  1094. X    int Origc;
  1095. X    char *FileWithMatches = (char *) 0;
  1096. X    char **MatchList;
  1097. X    int MatchCount = 0;
  1098. X
  1099. X    progname = argv[0];
  1100. X
  1101. X    SetDefaults(argc, argv);
  1102. X
  1103. X    /* All lq-text programs must call SetDefaults() before getopt, and
  1104. X     * must then be prepared to ignore options z with arg and Z without.
  1105. X     */
  1106. X    while ((ch = getopt(argc, argv, "a:b:f:o:z:ZVvx")) != EOF) {
  1107. X    switch (ch) {
  1108. X    case 'z':
  1109. X        break; /* done by SetDefaults(); */
  1110. X    case 'V':
  1111. X        fprintf(stderr, "%s version %s\n", progname, Revision);
  1112. X        break;
  1113. X    case 'v':
  1114. X        AsciiTrace = 1;
  1115. X        break;
  1116. X    case 'a': /* lines above */
  1117. X        LinesAbove = atoi(optarg); /* need cknum() */
  1118. X        break;
  1119. X    case 'b':
  1120. X        LinesBelow = atoi(optarg);
  1121. X        break;
  1122. X    case 'f':
  1123. X        FileWithMatches = optarg;
  1124. X        break;
  1125. X    case 'o': /* -o fd --- write the selected files to fp */
  1126. X        if (SelectedNames >= 0) {
  1127. X        fprintf(stderr,
  1128. X        "%s: -o %d -o %s: you must not give more than one -o option.\n",
  1129. X                    progname, SelectedNames, optarg);
  1130. X        ErrFlag = (-1);
  1131. X        } else {
  1132. X        if (!isdigit(*optarg)) {
  1133. X            fprintf(stderr, "%s: -o must be followed by a number\n",
  1134. X                                progname);
  1135. X            exit(1);
  1136. X        }
  1137. X        SelectedNames = atoi(optarg);
  1138. X        break;
  1139. X        }
  1140. X        break;
  1141. X    case 'x':
  1142. X        ErrFlag = (-1);
  1143. X        break;
  1144. X    case '?':
  1145. X    default:
  1146. X        ErrFlag = 1;
  1147. X    }
  1148. X    }
  1149. X
  1150. X    if (ErrFlag < 0) { /* -x or -xv was used */
  1151. X    fprintf(stderr, "usage: %s [-xv] [options] [matches...]\n", progname);
  1152. X    fprintf(stderr,
  1153. X    "use %s -x, -xv or -xvv for more detailed explanations.\n", progname);
  1154. X
  1155. X    if (AsciiTrace) {
  1156. X        DefaultUsage();
  1157. X        fprintf(stderr, "\n\
  1158. X    -a above - set the number of lines shown above each matching\n\
  1159. X           match to \"above\" [default is %d]\n", DFLTABOVE);
  1160. X        fprintf(stderr, "\
  1161. X    -b below - set the number of lines shown below each match\n\
  1162. X           match to \"above\" [default is %d]\n", DFLTBELOW);
  1163. X        fprintf(stderr, "\
  1164. X    -f file -- \"file\" contains a list of matches, one per line\n");
  1165. X    }
  1166. X    if (AsciiTrace > 1) {
  1167. X        fputs("\
  1168. X    Matches should be in the form of\n\
  1169. X        BlockNumber  WordInBlock  FileName\n\
  1170. X    where BlockBumber and WordInBlock are positive numbers.\n\
  1171. X    (This is the format produced by the lqword -l command.)\n\
  1172. X", stderr);
  1173. X    }
  1174. X    exit(0);
  1175. X    } else if (ErrFlag > 0) {
  1176. X    fprintf(stderr, "use %s -x for an explanation.\n", progname);
  1177. X    exit(1);
  1178. X    }
  1179. X
  1180. X    /* open the file for the selected output */
  1181. X    if (SelectedNames > 0) {
  1182. X    if ((InfoStream = fdopen(SelectedNames, "w")) == (FILE *) 0) {
  1183. X        int e = errno;
  1184. X
  1185. X        fprintf(stderr, "%s: -o %d: can't open stream ",
  1186. X                            progname, SelectedNames);
  1187. X        errno = e;
  1188. X        perror("for writing");
  1189. X        exit(1);
  1190. X    }
  1191. X    }
  1192. X
  1193. X    /* check that we can get at the file containing the matches, if one
  1194. X     * was supplied.
  1195. X     */
  1196. X    if (FileWithMatches) {
  1197. X    struct stat StatBuf;
  1198. X    char *msg = 0;
  1199. X
  1200. X    if (stat(FileWithMatches, &StatBuf) < 0) {
  1201. X        int e = errno; /* on many systems, fprintf() changes errno! */
  1202. X        fprintf(stderr, "%s: can't open match-list file ", FileWithMatches);
  1203. X        errno = e;
  1204. X        perror(progname);
  1205. X        exit(1);
  1206. X    } else if (AsciiTrace) {
  1207. X        switch (StatBuf.st_mode & S_IFMT) {
  1208. X        case S_IFDIR:
  1209. X        fprintf(stderr,
  1210. X        "%s: ca't read matches from \"%s\" -- it's a directory!\n",
  1211. X                        progname, FileWithMatches);
  1212. X        exit(1);
  1213. X        case S_IFREG:
  1214. X        break;
  1215. X#ifdef S_IFIFO
  1216. X        case S_IFIFO:
  1217. X        msg = "named pipe or fifo";
  1218. X        /* fall through */
  1219. X#endif
  1220. X        case S_IFCHR:
  1221. X        if (!msg) msg = "raw special device";
  1222. X        /* fall through */
  1223. X        case S_IFBLK:
  1224. X        if (!msg) msg = "block special device";
  1225. X        /* fall through */
  1226. X#ifdef S_IFNAM
  1227. X        case S_IFNAM:
  1228. X        if (!msg) msg = "named special file"; /* wot dat? */
  1229. X        /* fall through */
  1230. X#endif
  1231. X        default:
  1232. X        if (!msg) msg = "special file";
  1233. X
  1234. X        fprintf(stderr,
  1235. X            "%s: warning: file \"%s\" containing matches is a %s\n",
  1236. X            progname, FileWithMatches, msg);
  1237. X        
  1238. X        /* but continue anyway... */
  1239. X
  1240. X        }
  1241. X    }
  1242. X    /* Now read the file, and make an array of matches... */
  1243. X    if (ReadMatchFile(FileWithMatches, StatBuf.st_size, &MatchCount, &MatchList) < 0) {
  1244. X        fprintf(stderr, "%s: couldn't read matches from \"%s\"\n",
  1245. X                        progname, FileWithMatches);
  1246. X        exit(1);
  1247. X    }
  1248. X    }
  1249. X
  1250. X    argv += optind;
  1251. X    argc -= optind;
  1252. X
  1253. X    if (MatchCount) {
  1254. X    argc = MatchCount;
  1255. X    argv = MatchList;
  1256. X    }
  1257. X
  1258. X    if (argc < 3) {
  1259. X    fprintf(stderr,
  1260. X    "%s: matches must have at least 3 parts; use -xv for an explanation\n",
  1261. X                                progname);
  1262. X    exit(1);
  1263. X    } else if (argc % 3) {
  1264. X    /* Note: I could detect lqword output here (i.e., without -l) */
  1265. X    fprintf(stderr, "%s: can't understand match format;\n", progname);
  1266. X    fprintf(stderr, "%s: use -xv for more explanation.\n", progname);
  1267. X    exit(1);
  1268. X    }
  1269. X
  1270. X    Origv = argv;
  1271. X    Origc = argc;
  1272. X
  1273. X    ThisRow = DISPLAY_TOP - 1;
  1274. X    NumberOfFiles = argc / 3;
  1275. X
  1276. X    initscr();
  1277. X    nonl();
  1278. X    raw();
  1279. X    noecho();
  1280. X
  1281. X    while (argc > 0) {
  1282. X    char Buffer[120];
  1283. X    int Where;
  1284. X
  1285. X    ThisRow = DISPLAY_TOP;
  1286. X    ThisCol = (-1);
  1287. X    ShowFile(argv[2], atol(*argv), (unsigned) atoi(argv[1]), argc - Origc);
  1288. X    (void) sprintf(Buffer, "Match %d of %d", 
  1289. X                NumberOfFiles - (argc / 3) + 1, NumberOfFiles);
  1290. X    Where = COLS - (strlen(Buffer) + 10);
  1291. X    mvwaddstr(stdscr, LINES - 1, Where, Buffer);
  1292. X    refresh();    /* Where (above) is in case mvwaddstr is a macro */
  1293. X
  1294. X    if (argc > 0) {
  1295. X        attrset(A_STANDOUT);
  1296. X        mvwaddstr(stdscr, LINES - 1, 0, "[Press SPACE to continue]");
  1297. X        attrset(0);
  1298. X        wmove(stdscr, 0, 0);
  1299. X        (void) refresh();
  1300. X        switch (getch()) {
  1301. X        case '?':
  1302. X        case 'x':
  1303. X        case 'h':
  1304. X        case 'i':
  1305. X#ifdef KEY_HELP
  1306. X        case KEY_HELP:
  1307. X#endif
  1308. X        {
  1309. X            WINDOW *HelpWin = newwin(12, 40, 5, (COLS - 40) / 2);
  1310. X
  1311. X            if (HelpWin == (WINDOW *) 0) {
  1312. X            beep();
  1313. X            } else {
  1314. X#ifndef ACS_HLINE
  1315. X            box(HelpWin, '#', '#');
  1316. X#else
  1317. X            box(HelpWin, 0, 0);
  1318. X            /* Versions of curses with ASC_HLINE take 0 to
  1319. X             * mean that line-drawing should be done
  1320. X             * "properly".
  1321. X             */
  1322. X#endif
  1323. X            wmove(HelpWin, 1, 2);
  1324. X            mvwprintw(HelpWin, 1,2, "x, ?    -- print this explanation");
  1325. X            mvwprintw(HelpWin, 2,2, "space   -- go to next match");
  1326. X            mvwprintw(HelpWin, 3,2, "return  -- go to next match");
  1327. X            mvwprintw(HelpWin, 4,2, "0, ^, F -- go to First match");
  1328. X            mvwprintw(HelpWin, 5,2, "$, L    -- go to the Last match");
  1329. X            mvwprintw(HelpWin, 6,2, "n, +    -- go to the next file");
  1330. X            mvwprintw(HelpWin, 7,2, "p, -    -- go to previous file");
  1331. X            mvwprintw(HelpWin, 8,2, "s, g    -- save this filename");
  1332. X            mvwprintw(HelpWin, 9,2, "u, d    -- drop this filename");
  1333. X            mvwprintw(HelpWin, 10,2, "q, Q    -- quit browsing");
  1334. X            wrefresh(HelpWin);
  1335. X            (void) getch();
  1336. X            delwin(HelpWin);
  1337. X#ifndef CURSESX /* This is because 4.2 BSD a brain-dead curses... */
  1338. X            clearok(stdscr, TRUE);
  1339. X            wrefresh(stdscr);
  1340. X#endif
  1341. X            }
  1342. X        }
  1343. X        break;
  1344. X        case 'q':
  1345. X        case 'Q':
  1346. X        goto AllDone;
  1347. X            /* the goto is to surmount an AT&T compiler bug */
  1348. X        case '0': /* reset to beginning */
  1349. X        case '1':
  1350. X        case 'f':  case 'F':
  1351. X        case '^': case '6': /* (6 is often unshifted ^) */
  1352. X        argc = Origc;
  1353. X        argv = Origv;
  1354. X        break;
  1355. X        case '$': /* to the end */
  1356. X        case 'l': case 'L': /* Last match */
  1357. X        argv += (argc - 3);
  1358. X        argc = 3;
  1359. X        break;
  1360. X        case 'v': /* view the file -- use PAGER */
  1361. X        {
  1362. X            char Buffer[4096];
  1363. X            char *doc;
  1364. X            int e = errno;
  1365. X
  1366. X            if ((doc = FindFile(argv[2])) == (char *) 0) {
  1367. X            errno = e;
  1368. X            perror(argv[2]);
  1369. X            sleep(2);
  1370. X            goto AllDone;
  1371. X            }
  1372. X
  1373. X            (void) sprintf(Buffer, "%s \"%s\"", PAGER, doc);
  1374. X            (void) MySystem(Buffer);
  1375. X            clearok(stdscr, TRUE);
  1376. X            wrefresh(stdscr);
  1377. X        }
  1378. X        break;
  1379. X        case 's': /* keep this filename for later use */
  1380. X        case 'k': case 'g': /* keep, get */
  1381. X        fprintf(InfoStream, "%c %s\n", 's', argv[2]);
  1382. X        break; /*NOTDONE*/
  1383. X        case 'd': /* delete this file from the list */
  1384. X        fprintf(InfoStream, "%c %s\n", 'd', argv[2]);
  1385. X        break; /* NOTDONE */
  1386. X        case 'R': /* revert to initial state */
  1387. X        break; /* NOTDONE*/
  1388. X        case '-':
  1389. X        case 'p':
  1390. X        {
  1391. X            char *p = argv[2];
  1392. X            char **Argv = argv;
  1393. X            int Argc = argc;
  1394. X
  1395. X            while (Argc + 3 <= Origc && STREQ(Argv[2], p)) {
  1396. X            Argv -= 3;
  1397. X            Argc += 3;
  1398. X            }
  1399. X
  1400. X            if (Argc == argc) {
  1401. X            beep();
  1402. X            } else {
  1403. X            argv = Argv;
  1404. X            argc = Argc;
  1405. X            }
  1406. X        }
  1407. X        break;
  1408. X        case '+':
  1409. X        case 'n':
  1410. X        {
  1411. X            char *p = argv[2];
  1412. X            char **Argv = argv;
  1413. X            int Argc = argc;
  1414. X
  1415. X            while (Argc > 3 && STREQ(Argv[2], p)) {
  1416. X            Argv += 3;
  1417. X            Argc -= 3;
  1418. X            }
  1419. X
  1420. X            if (Argc == argc) {
  1421. X            beep();
  1422. X            } else {
  1423. X            argv = Argv;
  1424. X            argc = Argc;
  1425. X            }
  1426. X        }
  1427. X        break;
  1428. X        case 'R' ^ 64: /* control-R */
  1429. X        case 'L' ^ 64: /* control-L */
  1430. X        clearok(stdscr, TRUE);
  1431. X        wrefresh(stdscr);
  1432. X        break;
  1433. X        case '=':
  1434. X        clearok(stdscr, TRUE);
  1435. X        wrefresh(stdscr);
  1436. X        {
  1437. X            FILE *Pager = popen(PAGER, "w");
  1438. X            char **p;
  1439. X            int i;
  1440. X
  1441. X            if (!p) {
  1442. X            beep();
  1443. X            break;
  1444. X            }
  1445. X            for (p = Origv, i = Origc; i > 0; i -= 3, p += 3) {
  1446. X            (void) fprintf(Pager, "%s\n", *p);
  1447. X            }
  1448. X            (void) pclose(Pager);
  1449. X        }
  1450. X        clearok(stdscr, TRUE);
  1451. X        wrefresh(stdscr);
  1452. X        break;
  1453. X        case ' ':
  1454. X        case '\r':
  1455. X        case '\n':
  1456. X        argv += 3;
  1457. X        argc -= 3;
  1458. X        break;
  1459. X        default:
  1460. X        beep();
  1461. X        break;
  1462. X        }
  1463. X    }
  1464. X    }
  1465. X
  1466. XAllDone:
  1467. X    wmove(stdscr, LINES - 1, 0);
  1468. X    clrtoeol();
  1469. X    /* Try to revent the screen from scrolling when we exit */
  1470. X    wmove(stdscr, LINES - 2, 0);
  1471. X    refresh();
  1472. X    endwin();
  1473. X    return 0;
  1474. X}
  1475. X
  1476. Xint
  1477. XReadMatchFile(FileWithMatches, FileSize, MatchCount, MatchList)
  1478. X    char *FileWithMatches;
  1479. X    off_t FileSize;
  1480. X    int *MatchCount;
  1481. X    char ** *MatchList;
  1482. X{
  1483. X    extern char *strtok();
  1484. X
  1485. X    int fd;
  1486. X    char **Result;
  1487. X    char *StorageArea;
  1488. X    char *p;
  1489. X    unsigned int n_matches;
  1490. X    int BytesRead;
  1491. X    int i;
  1492. X    char *NextStr;
  1493. X
  1494. X    if (!FileWithMatches || !*FileWithMatches) {
  1495. X    fprintf(stderr, "%s: match-list file (from -f) has empty name!\n",
  1496. X                                progname);
  1497. X    exit(1);
  1498. X    }
  1499. X
  1500. X    if ((fd = open(FileWithMatches, O_RDONLY)) == 0) {
  1501. X    int e = errno;
  1502. X    fprintf(stderr, "%s: can't open match-list file ", progname);
  1503. X    errno = e;
  1504. X    perror(FileWithMatches);
  1505. X    exit(1);
  1506. X    }
  1507. X
  1508. X    /* We know the number of bytes, and each space or newline will get
  1509. X     * turned into a null, so here goes...
  1510. X     * The +1 below is to ensure that there is space for a \0, even if a
  1511. X     * pesky user didn't put a \n at * the end of the file...
  1512. X     * Sometimes I hate emacs...
  1513. X     */
  1514. X    if ((StorageArea = malloc((unsigned) FileSize + 1)) == (char *) 0) {
  1515. X    fprintf(stderr, "%s: not enough memory to read match-list \"%s\"\n",
  1516. X                            progname, FileWithMatches);
  1517. X    exit(1);
  1518. X    }
  1519. X
  1520. X    /* now read the list... */
  1521. X    if ((BytesRead = read(fd, StorageArea, FileSize)) != FileSize) {
  1522. X    if (BytesRead < 0) {
  1523. X        int e = errno;
  1524. X
  1525. X        fprintf(stderr, "%s: couldn't read %u bytes from ",
  1526. X                            progname, FileSize);
  1527. X        errno = e;
  1528. X        perror(FileWithMatches);
  1529. X        exit(1);
  1530. X    } else {
  1531. X        int e = errno;
  1532. X
  1533. X        fprintf(stderr, "%s: ", progname);
  1534. X        if (BytesRead > 4) { /* minimum plausible for 3 items */
  1535. X        fprintf(stderr, "warning: ");
  1536. X        }
  1537. X        fprintf(stderr, "only read %u bytes, not %u, from file ",
  1538. X                        progname, BytesRead, FileSize);
  1539. X        errno = e;
  1540. X        if (errno) perror(FileWithMatches);
  1541. X        else fprintf(stderr, "\"%s\"\n", FileWithMatches);
  1542. X
  1543. X        if (BytesRead <= 4) exit(1);
  1544. X
  1545. X        StorageArea = realloc(StorageArea, (unsigned) (BytesRead + 1));
  1546. X        if (StorageArea == (char *) 0) { /* unlikely, it got smaller  */
  1547. X        fprintf(stderr, "%s: can't realloc for \"%s\"\n",
  1548. X                        progname, FileWithMatches);
  1549. X        exit(1);
  1550. X        }
  1551. X        FileSize = BytesRead;
  1552. X    }
  1553. X    }
  1554. X
  1555. X    /* null-terminate it */
  1556. X    StorageArea[FileSize] = '\0';
  1557. X
  1558. X    /* got the data, now make an array... first, count the matches */
  1559. X    for (n_matches = 1, p = StorageArea; p - StorageArea < FileSize; p++) {
  1560. X    if isspace(*p) ++n_matches;
  1561. X    }
  1562. X
  1563. X    /* If there *was* trailing new-line, we overestimated by one.
  1564. X     * This doesn't matter.  If memory is that tight, initscr() will fail.
  1565. X     * In any case, allow extra space for a trailing null entry.
  1566. X     */
  1567. X    ++n_matches;
  1568. X    if (n_matches < 3) n_matches = 3;
  1569. X
  1570. X    Result = (char **) malloc((unsigned) n_matches * sizeof(char *));
  1571. X    if (Result == (char **) 0) {
  1572. X    fprintf(stderr, "%s: out of memory reading match file \"%s\"\n",
  1573. X                        progname, FileWithMatches);
  1574. X    exit(1);
  1575. X    }
  1576. X
  1577. X    /* Now step through the Storage Area filling in the pointers to the args */
  1578. X    ;
  1579. X
  1580. X    NextStr = (char *) 0;
  1581. X    i = -1;
  1582. X    for (p = StorageArea; p - StorageArea <= BytesRead; p++) {
  1583. X    if (!NextStr) NextStr = p;
  1584. X    if (isspace(*p) || p - StorageArea == BytesRead) {
  1585. X        if (p - StorageArea != BytesRead) *p = '\0';
  1586. X        while (isspace(*p)) { /* eat multiple blanks */
  1587. X        p++;
  1588. X        }
  1589. X        if (++i >= n_matches) {
  1590. X        n_matches += 20;
  1591. X        if ((Result = (char **)
  1592. X            realloc((char *) Result, n_matches * sizeof(char *))) ==
  1593. X                                (char **) 0) {
  1594. X            fprintf(stderr,
  1595. X            "%s: out of memory [%u] in match-file \"%s\"\n",
  1596. X            progname, n_matches * sizeof(char *), FileWithMatches);
  1597. X            /* TODO -- return with fewer matches -- NOTDONE */
  1598. X            exit(1);
  1599. X        }
  1600. X        }
  1601. X        *p = '\0'; /* OK at the very end cos of the extra byte! */
  1602. X        Result[i] = NextStr;
  1603. X        NextStr = (char *) 0;
  1604. X    }
  1605. X    }
  1606. X
  1607. X    if (i + 2 < n_matches) {
  1608. X    Result = (char **) realloc((char *)Result,
  1609. X                    (unsigned) (i+2) * sizeof(char **));
  1610. X    if (Result == (char **) 0) {
  1611. X        fprintf(stderr, "%s: no memory for match-list from \"%s\"\n",
  1612. X                        progname, FileWithMatches);
  1613. X        exit(1);
  1614. X    }
  1615. X    }
  1616. X
  1617. X    if (close(fd) < 0) {
  1618. X    fprintf(stderr, "%s: warning: obscure problem closing %d (\"%s\")\n",
  1619. X                        progname, fd, FileWithMatches);
  1620. X    sleep(5);
  1621. X    }
  1622. X
  1623. X    (*MatchList) = Result;
  1624. X    return (*MatchCount = i);
  1625. X}
  1626. X
  1627. Xvoid
  1628. XShowFile(FileName, BlockInFile, WordInBlock, UniqueID)
  1629. X    char *FileName;
  1630. X    unsigned long BlockInFile;
  1631. X    unsigned int WordInBlock;
  1632. X    int UniqueID;
  1633. X{
  1634. X    static char *Buffer = 0;
  1635. X    int fd;
  1636. X    static unsigned int BufLen;
  1637. X    int AmountRead;
  1638. X    register char *p;
  1639. X    int LinesFound;
  1640. X    int InTargetWord = 0;
  1641. X    char *StartOfMyWord;
  1642. X    int ThisWord = 0;
  1643. X    unsigned long FirstLumpSize;
  1644. X    char *Start;
  1645. X    static int LastID = (-1);
  1646. X
  1647. X    if (UniqueID == LastID) {
  1648. X    return;
  1649. X    } else {
  1650. X    LastID = UniqueID;
  1651. X    }
  1652. X    wclear(stdscr);
  1653. X    ThisRow = DISPLAY_TOP;
  1654. X
  1655. X    if (Buffer == (char *) 0) {
  1656. X    BufLen = COLS * (LinesAbove + LinesBelow + 1) + 1;
  1657. X    if (BufLen < FileBlockSize * 3) BufLen = FileBlockSize * 3;
  1658. X    Buffer = emalloc(BufLen);
  1659. X    }
  1660. X
  1661. X    errno = 0;
  1662. X
  1663. X    if ((fd = open(FileName, O_RDONLY, 0)) < 0) {
  1664. X    int e = errno;
  1665. X    char *doc;
  1666. X
  1667. X    if ((doc = FindFile(FileName)) == (char *) 0) {
  1668. X        errno = e;
  1669. X        perror(FileName);
  1670. X        sleep(2);
  1671. X        return;
  1672. X    } else if ((fd = open(doc, O_RDONLY, 0)) < 0) {
  1673. X        perror(doc);
  1674. X        sleep(2);
  1675. X        return;
  1676. X    }
  1677. X    FileName = doc;
  1678. X    }
  1679. X
  1680. X    /* display a helpful message: */
  1681. X    move(DISPLAY_TOP, 0);
  1682. X    clrtoeol();
  1683. X    move(DISPLAY_TOP - 1, 0);
  1684. X    clrtoeol();
  1685. X    mvwprintw(stdscr, DISPLAY_TOP - 1, 0,
  1686. X        "Block %lu/Word %u in document: ", BlockInFile, WordInBlock);
  1687. X    attrset(A_UNDERLINE);
  1688. X    wprintw(stdscr, "%s", FileName);
  1689. X    attrset(0);
  1690. X
  1691. X    errno = 0;
  1692. X    if (lseek(fd, BlockInFile? (long) ((BlockInFile - 1) * FileBlockSize) : 0L,
  1693. X                                    0) < 0) {
  1694. X    perror("lseek");
  1695. X    sleep(2);
  1696. X    clearok(stdscr, TRUE);
  1697. X    close(fd);
  1698. X    return;
  1699. X    }
  1700. X
  1701. X    errno = 0;
  1702. X    if ((AmountRead = read(fd, Buffer, BufLen)) < MinWordLength) {
  1703. X    perror("read");
  1704. X    sleep(5);
  1705. X    close(fd);
  1706. X    clearok(stdscr, TRUE);
  1707. X    return;
  1708. X    }
  1709. X
  1710. X    /* clear the bottom bit of screen */
  1711. X    {
  1712. X    register int i;
  1713. X
  1714. X    for (i = ThisRow; i < LINES; i++) {
  1715. X        move(i, 0);
  1716. X        wclrtoeol(stdscr);
  1717. X    }
  1718. X    }
  1719. X
  1720. X    /** Find the required word */
  1721. X    if (BlockInFile) {
  1722. X    /* start 1 char before the end of the previous block */
  1723. X    StartOfMyWord = &Buffer[FileBlockSize - 1];
  1724. X    /* perhaps the last word of the previous block spans the block
  1725. X     * boundary?
  1726. X     */
  1727. X    while (WithinWord(*StartOfMyWord)) StartOfMyWord++;
  1728. X    if (StartOfMyWord < &Buffer[FileBlockSize]) {
  1729. X        StartOfMyWord = &Buffer[FileBlockSize];
  1730. X    }
  1731. X    } else {
  1732. X    StartOfMyWord = Buffer;
  1733. X    }
  1734. X
  1735. X    for (ThisWord = 0; ThisWord <= WordInBlock + 1; ThisWord++) {
  1736. Xbored:
  1737. X    /* skip to the start of a word */
  1738. X    while (!StartsWord(*StartOfMyWord)) {
  1739. X        ++StartOfMyWord;
  1740. X    }
  1741. X
  1742. X    Start = StartOfMyWord;
  1743. X
  1744. X    /* find the end of the word */
  1745. X    while (WithinWord(*StartOfMyWord)) {
  1746. X        if (*StartOfMyWord == '\'' && !EndsWord(StartOfMyWord[1])) break;
  1747. X        StartOfMyWord++;
  1748. X    }
  1749. X
  1750. X    /* Assert: StartOfMyWord points 1 character beyond the end of the
  1751. X     * word pointed to by Start
  1752. X     */
  1753. X    /* see if it's long enough */
  1754. X    if (StartOfMyWord - Start < MinWordLength) {
  1755. X        goto bored;
  1756. X    }
  1757. X
  1758. X#if 0
  1759. X    /* see if it is too common */
  1760. X    {
  1761. X        extern char *WordRoot();
  1762. X
  1763. X        t_WordInfo W;
  1764. X        register char *p, *q;
  1765. X        char RootBuf[MaxWordLength + 1];
  1766. X
  1767. X        for (p = RootBuf, q = Start; *q; p++, q++) {
  1768. X        if (q == StartOfMyWord) break;
  1769. X        *p = isupper(*q) ? tolower(*q) : *q;
  1770. X        }
  1771. X        *p = '\0';
  1772. X
  1773. X        W.Word = RootBuf;
  1774. X        W.Length = strlen(W.Word);
  1775. X        W.WordPlace.Flags = 0;
  1776. X
  1777. X        (void) WordRoot(&W);
  1778. X
  1779. X        if (TooCommon(&W)) goto bored;
  1780. X
  1781. X    }
  1782. X#endif
  1783. X
  1784. X    /** See if it's the right one */
  1785. X    if (ThisWord == WordInBlock) {
  1786. X        StartOfMyWord = Start;
  1787. X        break;
  1788. X    }
  1789. X    }
  1790. X
  1791. X    FirstLumpSize = StartOfMyWord - Buffer;
  1792. X
  1793. X    /* Find N lines before it */
  1794. X    LinesFound = 0;
  1795. X    for (p = StartOfMyWord; p > Buffer; --p) {
  1796. X    if (*p == '\n') {
  1797. X        if (++LinesFound > LinesAbove) break;
  1798. X    }
  1799. X    }
  1800. X
  1801. X    /* display them */
  1802. X    while (p < StartOfMyWord) {
  1803. X    Output(*p); /* Output might be a macro later */
  1804. X    p++;
  1805. X    }
  1806. X
  1807. X    /* find N lines after it */
  1808. X
  1809. X    LinesFound = 0;
  1810. X    while (p - Buffer < AmountRead) {
  1811. X    switch (InTargetWord) {
  1812. X    case 0:
  1813. X        if (StartsWord(*p)) {
  1814. X        attrset(A_STANDOUT);
  1815. X        InTargetWord = 1;
  1816. X        }
  1817. X        break;
  1818. X    case 1:
  1819. X        if (!WithinWord(*p)) {
  1820. X        InTargetWord = 2;
  1821. X        attrset(0);
  1822. X        }
  1823. X    }
  1824. X    Output(*p);
  1825. X
  1826. X    if (*p == '\n') {
  1827. X        if (++LinesFound > LinesBelow) break;
  1828. X    }
  1829. X    p++;
  1830. X    }
  1831. X
  1832. X    (void) refresh();
  1833. X
  1834. X    (void) close(fd);
  1835. X    return;
  1836. X}
  1837. X
  1838. Xvoid
  1839. XOutput(ch)
  1840. X    int ch;
  1841. X{
  1842. X    switch(ch) {
  1843. X    default:
  1844. X    if (++ThisCol > COLS) {
  1845. X        if (++ThisRow >= LINES - 1) {
  1846. X        ThisRow = DISPLAY_TOP;
  1847. X        }
  1848. X        ThisCol = 0;
  1849. X    }
  1850. X    if (ThisCol <= 0) {
  1851. X        ThisCol = 0;
  1852. X        move(ThisRow, ThisCol);
  1853. X        clrtoeol();
  1854. X    }
  1855. X    mvwaddch(stdscr, ThisRow, ThisCol, (chtype) ch);
  1856. X    break;
  1857. X    case '\n':
  1858. X    if (++ThisRow >= LINES - 1) {
  1859. X        ThisRow = DISPLAY_TOP;
  1860. X    }
  1861. X    ThisCol = (-1);
  1862. X    move(ThisRow, 0);
  1863. X    clrtoeol();
  1864. X    break;
  1865. X    case '\t':
  1866. X    ThisCol |= 7;
  1867. X    break;
  1868. X    case ' ':
  1869. X    ThisCol++;
  1870. X    }
  1871. X}
  1872. X
  1873. X/*
  1874. X * $Log:    lqshow.c,v $
  1875. X * Revision 1.9  91/03/03  00:18:26  lee
  1876. X * No longer needs to check common words.
  1877. X * 
  1878. X * Revision 1.8  90/10/06  00:50:58  lee
  1879. X * Prepared for first beta release.
  1880. X * 
  1881. X * Revision 1.7  90/10/05  23:49:25  lee
  1882. X * Moved the Match %d of %d message left somewhat.
  1883. X * 
  1884. X * Revision 1.6  90/10/03  21:26:47  lee
  1885. X * Removed BSD/SYSV diffs and used CURSESX instead.
  1886. X * 
  1887. X * Revision 1.5  90/08/29  21:45:34  lee
  1888. X * Alpha release
  1889. X * 
  1890. X * Revision 1.4  90/08/09  19:17:17  lee
  1891. X * BSD lint and Saber
  1892. X * 
  1893. X * Revision 1.3  90/07/11  10:57:46  lee
  1894. X * Added limited ultrix support...  also some small optimisations and
  1895. X * changes to the help screen.
  1896. X * 
  1897. X * Revision 1.2  90/04/21  16:06:24  lee
  1898. X * Cleaned up the gode for gcc -W
  1899. X * 
  1900. X * Revision 1.1  90/02/14  18:32:39  lee
  1901. X * Initial revision
  1902. X * 
  1903. X * Revision 2.1  89/10/02  01:15:51  lee
  1904. X * New index format, with Block/WordInBlock/Flags/BytesSkipped info.
  1905. X * 
  1906. X * Revision 1.3  89/09/17  23:04:04  lee
  1907. X * Various fixes; NumberInBlock now a short...
  1908. X * 
  1909. X * Revision 1.2  89/09/16  21:18:35  lee
  1910. X * First demonstratable version.
  1911. X * 
  1912. X * Revision 1.1  89/09/16  20:02:58  lee
  1913. X * Initial revision
  1914. X * 
  1915. X */
  1916. @@@End of lq-text/src/lqtext/lqshow.c
  1917. echo end of part 07
  1918. -- 
  1919. Liam R. E. Quin,  lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337
  1920.