lee@sq.sq.com (Liam R. E. Quin) (03/04/91)
: cut here --- cut here -- : To unbundle, sh this file #! /bin/sh : part 07 echo x - lq-text/src/lqtext/lqkwik.c 1>&2 sed 's/^X//' >lq-text/src/lqtext/lqkwik.c <<'@@@End of lq-text/src/lqtext/lqkwik.c' X/* lqkwik.c -- Copyright 1991 Liam R. Quin. All Rights Reserved. X * This code is NOT in the public domain. X * See the file COPYRIGHT for full details. X */ X X/* lqkwik -- produce a keyword-in-context list of matches... X * Liam R. Quin, February 1991 and later... X * X * $Id: lqkwik.c,v 1.1 91/03/02 20:37:47 lee Rel1-10 $ X */ X X#define COLS 65 /* the width of kwik word index */ X#define WORDCOL 25 /* where to put the word in the index */ X#define GAPWIDTH 2 /* space before the word itself */ X#define SCREENWIDTH 79 X Xint Cols = COLS; Xint WordCol = WORDCOL; Xint GapWidth = GAPWIDTH; Xint ScreenWidth = SCREENWIDTH; X Xstatic int LinesAbove = 5; Xstatic int linesBelow = 5; X X#include "globals.h" /* defines and declarations for database filenames */ X X#include <malloc.h> X#include <fcntl.h> X#include <ctype.h> X#include <sys/types.h> /* for fileinfo.h */ X#include <sys/stat.h> X X#include <stdio.h> X X#include "fileinfo.h" X#include "wordinfo.h" X#include "wordrules.h" X#include "pblock.h" X#include "emalloc.h" X X/** Unix system calls that need declaring: **/ Xextern long lseek(); Xextern int open(), close(); Xextern int read(); Xextern void exit(); Xextern int stat(); X X/** Unix/C Library Functions that need declaring: **/ X#ifndef tolower X extern int tolower(); X#endif Xextern int strlen(); Xextern int strcmp(); Xextern unsigned sleep(); Xextern int atoi(); Xextern long atol(); Xextern void perror(); X X/** lqtext library functions that need declaring: **/ Xextern int MySystem(); Xextern int TooCommon(); Xextern void SetDefault(); Xextern void DefaultUsage(); X X/** Functions within this file that are used before being defined: **/ Xint ReadMatchFile(); Xint ShowFile(); Xvoid Output(); X X/** **/ X X/** some useful macros: **/ X#define max(choir,boy) (((choir)>(boy))?(choir):(boy)) X#define min(choir,boy) (((choir)<(boy))?(choir):(boy)) X X/** **/ X Xint AsciiTrace = 0; X Xextern int errno; X Xchar *progname = "lqkwik"; /* set from argv[] in main() */ X Xint SelectedNames = -1; XFILE *InfoStream = 0; X Xstatic char *Revision = "@(#) showfile.c 2.2"; X Xint Xmain(argc, argv) X int argc; X char *argv[]; X{ X extern int optind, getopt(); X extern char *optarg; /* for getopt */ X int ch; /* for getopt */ X int ErrFlag = 0; /* see how getopt makes programs cleaner? */ X int NumberOfFiles; X char *FileWithMatches = (char *) 0; X char **MatchList; X int MatchCount = 0; X int Origc; X int Right = Cols - (WordCol + GapWidth); X int Left = WordCol - GapWidth; X X progname = argv[0]; X X SetDefaults(argc, argv); X X /* All lq-text programs must call SetDefaults() before getopt, and X * must then be prepared to ignore options z with arg and Z without. X */ X while ((ch = getopt(argc, argv, "a:b:f:l:r:g:w:o:z:ZVvx")) != EOF) { X switch (ch) { X case 'z': X break; /* done by SetDefaults(); */ X case 'V': X fprintf(stderr, "%s version %s\n", progname, Revision); X break; X case 'v': X AsciiTrace = 1; X break; X case 'f': X FileWithMatches = optarg; X break; X case 'g': X GapWidth = atoi(optarg); X break; X case 'l': X Left = atoi(optarg); X break; X case 'r': X Right = atoi(optarg); X break; X case 'w': X ScreenWidth = atoi(optarg); X break; X case 'x': X ErrFlag = (-1); X break; X case '?': X default: X ErrFlag = 1; X } X } X X if (ErrFlag < 0) { /* -x or -xv was used */ X fprintf(stderr, "usage: %s [-xv] [options] [matches...]\n", progname); X fprintf(stderr, X "use %s -x, -xv or -xvv for more detailed explanations.\n", progname); X X if (AsciiTrace) { X DefaultUsage(); X fprintf(stderr, "\n\ X -f file -- \"file\" contains a list of matches, one per line\n"); X fprintf(stderr, "\ X -g n -- set gap between text and matched phrase to n [%d]\n\ X -l n -- display n characters to the left of each phrase [%d]\n\ X -r n -- display r chars to the right of each phrase's start [%d]\n\ X -w n -- truncate the line after n characters [default: %d]\n", X GapWidth, X Left, X Right, X ScreenWidth X ); X } X if (AsciiTrace > 1) { X fputs("\ X Matches should be in the form of\n\ X BlockNumber WordInBlock FileName\n\ X where BlockBumber and WordInBlock are positive numbers.\n\ X (This is the format produced by the lqword -l command.)\n\ X", stderr); X } X exit(0); X } else if (ErrFlag > 0) { X fprintf(stderr, "use %s -x for an explanation.\n", progname); X exit(1); X } X X Cols = Left + Right + GapWidth; X WordCol = Left + GapWidth; X X if (AsciiTrace) { X fprintf(stderr,"Left:%d Right:%d Cols:%d Gap:%d WC:%d SW:%d\n", X Left, Right, Cols, GapWidth, WordCol,ScreenWidth); X } X X if (ScreenWidth <= Cols + 2) { X fprintf(stderr, X "%s: ScreenWidth %d, %d text cols -- no room for file names!\n", X progname, ScreenWidth, Cols); X exit(1); X } X X /* open the file for the selected output */ X if (SelectedNames > 0) { X if ((InfoStream = fdopen(SelectedNames, "w")) == (FILE *) 0) { X int e = errno; X X fprintf(stderr, "%s: -o %d: can't open stream ", X progname, SelectedNames); X errno = e; X perror("for writing"); X exit(1); X } X } X X /* check that we can get at the file containing the matches, if one X * was supplied. X */ X if (FileWithMatches) { X struct stat StatBuf; X char *msg = 0; X X if (stat(FileWithMatches, &StatBuf) < 0) { X int e = errno; /* on many systems, fprintf() changes errno! */ X fprintf(stderr, "%s: can't open match-list file ", FileWithMatches); X errno = e; X perror(progname); X exit(1); X } else if (AsciiTrace) { X switch (StatBuf.st_mode & S_IFMT) { X case S_IFDIR: X fprintf(stderr, X "%s: ca't read matches from \"%s\" -- it's a directory!\n", X progname, FileWithMatches); X exit(1); X case S_IFREG: X break; X#ifdef S_IFIFO X case S_IFIFO: X msg = "named pipe or fifo"; X /* fall through */ X#endif X case S_IFCHR: X if (!msg) msg = "raw special device"; X /* fall through */ X case S_IFBLK: X if (!msg) msg = "block special device"; X /* fall through */ X#ifdef S_IFNAM X case S_IFNAM: X if (!msg) msg = "named special file"; /* wot dat? */ X /* fall through */ X#endif X default: X if (!msg) msg = "special file"; X X fprintf(stderr, X "%s: warning: file \"%s\" containing matches is a %s\n", X progname, FileWithMatches, msg); X X /* but continue anyway... */ X X } X } X /* Now read the file, and make an array of matches... */ X if (ReadMatchFile(FileWithMatches, StatBuf.st_size, &MatchCount, &MatchList) < 0) { X fprintf(stderr, "%s: couldn't read matches from \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X } X X argv += optind; X argc -= optind; X X if (MatchCount) { X argc = MatchCount; X argv = MatchList; X } X X if (argc < 3) { X fprintf(stderr, X "%s: matches must have at least 3 parts; use -xv for an explanation\n", X progname); X exit(1); X } else if (argc % 3) { X /* Note: I could detect lqword output here (i.e., without -l) */ X fprintf(stderr, "%s: can't understand match format;\n", progname); X fprintf(stderr, "%s: use -xv for more explanation.\n", progname); X exit(1); X } X X Origc = argc; X X NumberOfFiles = argc / 3; X X while (argc > 0) { X int Where; X X if (ShowFile(argv[2], atol(*argv), (unsigned) atoi(argv[1])) < 0) { X int i; X X /* This avoids repeated messages about the same file */ X for (i = argc - 3; i > 0; i -= 3) { X if (STREQ(argv[2], argv[2 + 3])) { X argv += 3; X } else { X break; X } X } X argc = i + 3; /* so we can subtract 3 ... */ X X } X argv += 3; X argc -= 3; X } X X return 0; X} X Xint XReadMatchFile(FileWithMatches, FileSize, MatchCount, MatchList) X char *FileWithMatches; X off_t FileSize; X int *MatchCount; X char ** *MatchList; X{ X extern char *strtok(); X X int fd; X char **Result; X char *StorageArea; X char *p; X unsigned int n_matches; X int BytesRead; X int i; X char *NextStr; X X if (!FileWithMatches || !*FileWithMatches) { X fprintf(stderr, "%s: match-list file (from -f) has empty name!\n", X progname); X exit(1); X } X X if ((fd = open(FileWithMatches, O_RDONLY)) == 0) { X int e = errno; X fprintf(stderr, "%s: can't open match-list file ", progname); X errno = e; X perror(FileWithMatches); X exit(1); X } X X /* We know the number of bytes, and each space or newline will get X * turned into a null, so here goes... X * The +1 below is to ensure that there is space for a \0, even if a X * pesky user didn't put a \n at * the end of the file... X * Sometimes I hate emacs... X */ X if ((StorageArea = malloc((unsigned) FileSize + 1)) == (char *) 0) { X fprintf(stderr, "%s: not enough memory to read match-list \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X X /* now read the list... */ X if ((BytesRead = read(fd, StorageArea, FileSize)) != FileSize) { X if (BytesRead < 0) { X int e = errno; X X fprintf(stderr, "%s: couldn't read %u bytes from ", X progname, FileSize); X errno = e; X perror(FileWithMatches); X exit(1); X } else { X int e = errno; X X fprintf(stderr, "%s: ", progname); X if (BytesRead > 4) { /* minimum plausible for 3 items */ X fprintf(stderr, "warning: "); X } X fprintf(stderr, "only read %u bytes, not %u, from file ", X progname, BytesRead, FileSize); X errno = e; X if (errno) perror(FileWithMatches); X else fprintf(stderr, "\"%s\"\n", FileWithMatches); X X if (BytesRead <= 4) exit(1); X X StorageArea = realloc(StorageArea, (unsigned) (BytesRead + 1)); X if (StorageArea == (char *) 0) { /* unlikely, it got smaller */ X fprintf(stderr, "%s: can't realloc for \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X FileSize = BytesRead; X } X } X X /* null-terminate it */ X StorageArea[FileSize] = '\0'; X X /* got the data, now make an array... first, count the matches */ X for (n_matches = 1, p = StorageArea; p - StorageArea < FileSize; p++) { X if isspace(*p) ++n_matches; X } X X /* If there *was* trailing new-line, we overestimated by one. X * This doesn't matter. If memory is that tight, initscr() will fail. X * In any case, allow extra space for a trailing null entry. X */ X ++n_matches; X if (n_matches < 3) n_matches = 3; X X Result = (char **) malloc((unsigned) n_matches * sizeof(char *)); X if (Result == (char **) 0) { X fprintf(stderr, "%s: out of memory reading match file \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X X /* Now step through the Storage Area filling in the pointers to the args */ X ; X X NextStr = (char *) 0; X i = -1; X for (p = StorageArea; p - StorageArea <= BytesRead; p++) { X if (!NextStr) NextStr = p; X if (isspace(*p) || p - StorageArea == BytesRead) { X if (p - StorageArea != BytesRead) *p = '\0'; X while (isspace(*p)) { /* eat multiple blanks */ X p++; X } X if (++i >= n_matches) { X n_matches += 20; X if ((Result = (char **) X realloc((char *) Result, n_matches * sizeof(char *))) == X (char **) 0) { X fprintf(stderr, X "%s: out of memory [%u] in match-file \"%s\"\n", X progname, n_matches * sizeof(char *), FileWithMatches); X /* TODO -- return with fewer matches -- NOTDONE */ X exit(1); X } X } X *p = '\0'; /* OK at the very end cos of the extra byte! */ X Result[i] = NextStr; X NextStr = (char *) 0; X } X } X X if (i + 2 < n_matches) { X Result = (char **) realloc((char *)Result, X (unsigned) (i+2) * sizeof(char **)); X if (Result == (char **) 0) { X fprintf(stderr, "%s: no memory for match-list from \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X } X X if (close(fd) < 0) { X fprintf(stderr, "%s: warning: obscure problem closing %d (\"%s\")\n", X progname, fd, FileWithMatches); X sleep(5); X } X X (*MatchList) = Result; X return (*MatchCount = i); X} X Xint XShowFile(FileName, BlockInFile, WordInBlock) X char *FileName; X unsigned long BlockInFile; X unsigned int WordInBlock; X{ X static char *Buffer = 0; X int fd; X static unsigned int BufLen; X int AmountRead; X register char *p; X register char *q; X int InTargetWord = 0; X char *StartOfMyWord; X int ThisWord = 0; X char *Start; X char *ThisLine = emalloc(Cols + 1); /* +1 for trailing \0 */ X char *FirstBit = emalloc(WordCol - GapWidth + 1); /* +1 for trailing \0 */ X char *LastBit = emalloc(Cols - WordCol + 1); /* +1 for trailing \0 */ X char *FirstStart; X X if (Buffer == (char *) 0) { X BufLen = Cols * 10; X if (BufLen < FileBlockSize * 3) BufLen = FileBlockSize * 3; X Buffer = emalloc(BufLen); X } X X errno = 0; X X if ((fd = open(FileName, O_RDONLY, 0)) < 0) { X int e = errno; X char *doc; X X if ((doc = FindFile(FileName)) == (char *) 0) { X fprintf(stderr, "%s: %s: ", progname, FileName); X errno = e; X perror(FileName); X efree(ThisLine); efree(FirstBit); efree(LastBit); X return -1; X } else if ((fd = open(doc, O_RDONLY, 0)) < 0) { X fprintf(stderr, "%s: %s: ", progname, FileName); X errno = e; X perror(doc); X efree(ThisLine); efree(FirstBit); efree(LastBit); X return -1; X } X FileName = doc; X } X X errno = 0; X if (lseek(fd, BlockInFile? (long) ((BlockInFile - 1) * FileBlockSize) : 0L, X 0) < 0) { X int e = errno; X fprintf(stderr, "%s: %s: ", progname, FileName); X errno = e; X perror("lseek"); X efree(ThisLine); efree(FirstBit); efree(LastBit); X return; X } X X errno = 0; X if ((AmountRead = read(fd, Buffer, BufLen)) < MinWordLength) { X int e = errno; X fprintf(stderr, "%s: %s: ", progname, FileName); X errno = e; X perror("read"); X efree(ThisLine); efree(FirstBit); efree(LastBit); X return -1; X } X X X /** Find the required word */ X if (BlockInFile) { X /* start 1 char before the end of the previous block */ X StartOfMyWord = &Buffer[FileBlockSize - 1]; X /* perhaps the last word of the previous block spans the block X * boundary? X */ X while (WithinWord(*StartOfMyWord)) StartOfMyWord++; X if (StartOfMyWord < &Buffer[FileBlockSize]) { X StartOfMyWord = &Buffer[FileBlockSize]; X } X } else { X StartOfMyWord = Buffer; X } X X (void) close(fd); X X for (ThisWord = 0; ThisWord <= WordInBlock + 1; ThisWord++) { Xbored: X /* skip to the start of a word */ X while (!StartsWord(*StartOfMyWord)) { X ++StartOfMyWord; X } X X Start = StartOfMyWord; X X /* find the end of the word */ X while (WithinWord(*StartOfMyWord)) { X if (*StartOfMyWord == '\'' && !EndsWord(StartOfMyWord[1])) break; X StartOfMyWord++; X } X X /* Assert: StartOfMyWord points 1 character beyond the end of the X * word pointed to by Start X */ X /* see if it's long enough */ X if (StartOfMyWord - Start < MinWordLength) { X goto bored; X } X X /** See if it's the right one */ X if (ThisWord == WordInBlock) { X StartOfMyWord = Start; X break; X } X } X X X /* Find context before the keyword */ X X q = &FirstBit[WordCol - GapWidth]; X *q-- = '\0'; X X for (p = StartOfMyWord - 1; p >= Buffer; --p, --q) { X *q = (isspace(*p)) ? ' ' : *p; X if (q == FirstBit) break; X } X X FirstStart = q; X X /* now build up the rest of the buffer */ X X q = LastBit; X *q = '\0'; X X InTargetWord = 0; X X for (p = StartOfMyWord; p - Buffer < AmountRead; p++) { X if (q >= &LastBit[Cols - WordCol]) break; X X switch (InTargetWord) { X case 0: X if (StartsWord(*p)) { X InTargetWord = 1; X } X break; X case 1: X if (!WithinWord(*p)) { X InTargetWord = 2; X } X } X if (isspace(*p)) { X *q = ' '; X } else { X *q = *p; X } X *++q = '\0'; X if (q >= &LastBit[Cols - WordCol]) break; X } X X printf("%*.*s", WordCol - GapWidth, WordCol - GapWidth, FirstStart); X X /* do the gap */ X { X X register int i; X X for (i = GapWidth; i > 0; i--) { X putchar(' '); X } X } X X printf("%-*.*s", Cols - WordCol, Cols - WordCol, LastBit); X X printf(":"); X { X int OverShoot = Cols + 2 + strlen(FileName) - ScreenWidth; /* +2 is ": " */ X X if (OverShoot > 0) { X FileName += OverShoot + 2; X printf("..."); X } else { X putchar(' '); X } X X } X printf("%s\n", FileName); X X efree(ThisLine); efree(FirstBit); efree(LastBit); X return 0; X} X X X/* X * $Log: lqkwik.c,v $ X * Revision 1.1 91/03/02 20:37:47 lee X * Initial revision X * X * X */ @@@End of lq-text/src/lqtext/lqkwik.c echo x - lq-text/src/lqtext/lqphrase.c 1>&2 sed 's/^X//' >lq-text/src/lqtext/lqphrase.c <<'@@@End of lq-text/src/lqtext/lqphrase.c' X/* lqphrase.c -- Copyright 1989, 1990 Liam R. Quin. All Rights Reserved. X * This code is NOT in the public domain. X * See the file COPYRIGHT for full details. X * X * $Id: lqphrase.c,v 1.4 90/10/06 00:50:56 lee Rel1-10 $ X */ X X/* lqphrase, part of Liam Quin's text retrieval package... X * X * lqphrase is intended to be an example of one way to use the programming X * interface to lq-text. X * X * The idea is quite simple: X * Simply take a phrase p, held in a string (char *p), and call X * t_Phrase *Phrase = String2Phrase(p); X * The result, if not null, contains only one interesting thing at this X * point: X * Phrase->ModifiedString X * is the canonical version of p -- with common and short words removed. X * for example, X * p = "The boy sat down in His Boat and playd with his toes."; X * might result in Phrase->ModifiedString containing X * "[*the] boy sat down [in] [*his] boat [*and] [?playd] with [*his] toe" X * Common words are marked with a *, and unknown words with ?. X * An attempt may have been made to reduce plurals. X * Since this phrase contains a word not in the database (playd), it will X * never match anything. As a result, it is a good idea to print this string X * (possibly massaging it first) so users can see what is going on. If you X * have it, the curses-based "lqtext" does this. X * X * If we change "playd" to "played", the above string is equivalent to X * "[*the] boy sat down [xx] [*the] boat [*the] played with [*the] toe" X * In other words, all common words are equivalent. The package remembers X * that one or more common words were skipped, and also that one or more X * lumps of letters too small to make up a word were skipped. X * The following are equivalent: X * L.R.E. Quin L. Quin L.R.Quin X.X.Quin X * in a QUIN a QuIn X * and the following are not the same as those: X * Quin (no preceding garbage) X * L.R.E. quin (first letter of `Quin' is not upper case (the rest is ignored) X * [*the] Quin (common words are not the same as skipped letters) X * L. Quin's (the presence of the posessive ('s) is significant) X * L. Quins (plural (two Quins) not the same as singular) X * L. Quinn (spelt incorrectly!) X * X * Now, having sorted that out, we have our canonical string (and lots of X * other things) in Phrase, so we can now call X * MakeMatches(Phrase); X * This will return the number of matches (*NOT* the number of files) for X * the given ModifiedPhrase in the database. X * This can take several seconds, so again, it can be worth printing out X * the modified string as soon as it is available, so the user is looking at X * that whilst MakeMatches is working! I have experimented with faster X * versions of MakeMatches involving binary search, but the extra complexity X * slowed things down on smaller databases. I don't have enough disk space X * here to make a large enough database to do real timings, sorry. X * X * Now we have done MakeMatches, we can marck along the linked list of X * pointers to linked lists of arrays of matches. Clear? No? Well, X * that's why there's en axample. See Match() below. X * X * Now, each match currently gives us X * t_FID FID; Files are numbered from 1 in the database X * unsigned long BlockInFile; -- the block in the file X * unsigned char WordInBlock; -- the word in the block X * unsigned char StuffBefore; -- the amount of leading garbage X * unsigned char Flags, including (see wordrules.h): X * X * WPF_WASPLURAL The word... ended in s X * WPF_UPPERCASE ...Started with a capital letter X * WPF_POSSESSIVE ...ended in 's X * WPF_ENDEDINING ...ended in ing X * WPF_LASTWASCOMMON the previous word was common X * WPF_LASTHADLETTERS we skipped some letters to get here X * WPF_LASTINBLOCK I'm the last word in this block X * X */ X X#include "globals.h" /* defines and declarations for database filenames */ X X#include <stdio.h> /* stderr, also for fileinfo.h */ X#include <fcntl.h> X#include <sys/types.h> X#include <malloc.h> X#include "emalloc.h" X#include "fileinfo.h" /* for wordinfo.h */ X#include "wordinfo.h" X#include "pblock.h" X#include "phrase.h" X X#ifndef STREQ X# define STREQ(boy,girl) ((*(boy) == *(girl)) && (!strcmp((boy),(girl)))) X#endif X Xextern int AsciiTrace; Xextern t_PhraseCaseMatch PhraseMatchLevel; X X/** System calls and functions... **/ X/** Unix system calls used in this file: **/ Xextern void exit(); X X/** Unix Library Functions used: **/ X/** lqtext library functions: **/ Xextern void SetDefaults(); Xextern void DefaultUsage(); X X/** functions used before they're defined within this file: **/ Xvoid Match(); X/** **/ X Xstatic char *Revision = "@(#) $Id: lqphrase.c,v 1.4 90/10/06 00:50:56 lee Rel1-10 $"; X Xchar *progname = "tryphrase"; X Xint SilentMode = 0; /* don't print matches if set to one */ X Xint Xmain(argc, argv) X int argc; X char *argv[]; X{ X extern int optind, getopt(); X /** extern char *optarg; (unused at present) **/ X int ch; X int ErrorFlag = 0; X X progname = argv[0]; X X SetDefaults(argc, argv); X X while ((ch = getopt(argc, argv, "Zz:ahpslxVv")) != EOF) { X switch (ch) { X case 'z': X case 'Z': X break; /* done by SetDefaults(); */ X case 'V': X fprintf(stderr, "%s version %s\n", progname, Revision); X break; X case 'v': /* same as -t 1 */ X AsciiTrace = 1; X break; X case 'l': X break; /* list mode is the default */ X case 's': X SilentMode = 1; X break; X case 'x': X ErrorFlag = (-1); X break; X case '?': X ErrorFlag = 1; X } X } X X /* Normally put call to lrqError here to give a helpful message, X * but not yet ready to ship the error handling package, sorry X */ X if (ErrorFlag) { X fprintf(stderr, "Usage: %s [options] \"phrase\" [...]\n", progname); X fprintf(stderr, "%s: options are:\n", progname); X fputs("\ X -l -- list mode, suitable for lqshow (the default)\n\ X -s -- silent mode; exit status indicates success of matching\n\ X\n", stderr); X X DefaultUsage(); X exit( ErrorFlag > 0 ? 1 : 0); /* 0 means -x was used */ X } X X if (AsciiTrace > 1) { X switch (PhraseMatchLevel) { X case PCM_HalfCase: X fprintf(stderr, "%s: Matching phrases heuristically.\n", progname); X break; X case PCM_SameCase: X fprintf(stderr, "%s: Matching phrases precisely.\n", progname); X break; X case PCM_AnyCase: X fprintf(stderr, "%s: Matching phrases approximately.\n", progname); X break; X default: X fprintf(stderr, "%s: internall error, case matching is %d\n", X progname, PhraseMatchLevel); X exit(2); X } X } X X while (optind < argc) { X Match(argv[optind++]); X } X X if (SilentMode) { X /* if we got to here we didn't find anything */ X exit(1); X } X return 0; X} X Xvoid XMatch(Phrase) X char *Phrase; X{ X extern t_Phrase *String2Phrase(); X extern t_FileInfo *GetFileInfo(); X extern long MakeMatches(); X X t_Phrase *P; X t_MatchList *Matches; X t_FID LastFID = (t_FID) 0; X t_FileInfo *FileInfo = 0; X X if (!Phrase || !*Phrase) return; X if ((P = String2Phrase(Phrase)) == (t_Phrase *) 0) return; X X if (MakeMatches(P) <= 0L) return; X X if (P) { X for (Matches = P->Matches; Matches != (t_MatchList *) 0; X Matches = Matches->Next) { X if (Matches->Match != (t_Match *) 0) { X if (Matches->Match->Where->FID != LastFID) { X t_FID FID = Matches->Match->Where->FID; X /*TODO: use DestroyFileInfo instead of efree:... */ X if (FileInfo) efree((char *) FileInfo); X if ((FileInfo = GetFileInfo(FID)) == (t_FileInfo *) 0) { X continue; X } X LastFID = FID; X } X X /* Now that we know that we have something to print... */ X if (SilentMode) { X exit(0); /* OK, found something */ X } X if (AsciiTrace) { X printf("%-7lu %-7u %-3d %-3d %s\n", X Matches->Match->Where->BlockInFile, X (unsigned) Matches->Match->Where->WordInBlock, X (unsigned) Matches->Match->Where->StuffBefore, X (unsigned) Matches->Match->Where->Flags, X FileInfo->Name); X } else { X printf("%-7.7lu %-7.7u %s\n", X Matches->Match->Where->BlockInFile, X Matches->Match->Where->WordInBlock, X FileInfo->Name); X } X } X } X } X} X X/* X * $Log: lqphrase.c,v $ X * Revision 1.4 90/10/06 00:50:56 lee X * Prepared for first beta release. X * X * Revision 1.3 90/08/29 21:45:29 lee X * Alpha release X * X * Revision 1.2 90/08/09 19:17:16 lee X * *** empty log message *** X * X * Revision 1.1 90/03/24 20:22:49 lee X * Initial revision X * X */ X @@@End of lq-text/src/lqtext/lqphrase.c echo x - lq-text/src/lqtext/lqshow.c 1>&2 sed 's/^X//' >lq-text/src/lqtext/lqshow.c <<'@@@End of lq-text/src/lqtext/lqshow.c' X/* lqshow.c -- Copyright 1989, 1990 Liam R. Quin. All Rights Reserved. X * This code is NOT in the public domain. X * See the file COPYRIGHT for full details. X */ X X/* lqshow -- show a file according to keywords, highlighting matches X * Liam R. Quin, September 1989 and later... X * X * $Id: lqshow.c,v 1.9 91/03/03 00:18:26 lee Rel1-10 $ X */ X X#include "globals.h" /* defines and declarations for database filenames */ X X#ifdef SYSV X /* for lint: */ X extern int w32addch(); X#endif X#ifdef ultrix X# include <cursesX.h> X#else X# include <curses.h> X#endif X#include <malloc.h> X#include <fcntl.h> X#include <ctype.h> X#include <sys/types.h> /* for fileinfo.h */ X#include <sys/stat.h> X X/* Check for old (or BSD) curses: */ X#ifndef A_STANDOUT X# define A_STANDOUT 10193 /* random */ X# define A_UNDERLINE 312 X# define attrset(a) ((a == 0) ? standend() : standout()) Xtypedef char chtype; /* long on sysV */ Xbeep() { X fprintf(stderr, "\007"); X fflush(stderr); X} X#endif X X#include "fileinfo.h" X#include "wordinfo.h" X#include "wordrules.h" X#include "pblock.h" X#include "emalloc.h" X X/** Unix system calls that need declaring: **/ Xextern long lseek(); Xextern int open(), close(); Xextern int read(); Xextern void exit(); Xextern int stat(); X X/** Unix/C Library Functions that need declaring: **/ X#ifndef tolower X extern int tolower(); X#endif Xextern int strlen(); Xextern int strcmp(); Xextern unsigned sleep(); Xextern int atoi(); Xextern long atol(); Xextern void perror(); X X/** Curses library functions: **/ X#ifdef SYSV Xextern int box32(); X#endif X#ifndef nonl X extern int nonl(); X#endif /**nonl*/ X#ifndef noecho Xextern int noecho(); X#endif X#ifndef wmove X extern int wmove(); X#endif X#ifndef waddstr X extern int waddstr(); X#endif X#ifndef wrefresh X extern int wrefresh(); X#endif X#ifndef beep X extern int beep(); X#endif X#ifndef wprintw X extern int printw(); X#endif Xextern int mvwprintw(), delwin(), wclear(), wclrtoeol(), endwin(); X X/** lqtext library functions that need declaring: **/ Xextern int MySystem(); Xextern int TooCommon(); Xextern void SetDefault(); Xextern void DefaultUsage(); X X/** Functions within this file that are used before being defined: **/ Xint ReadMatchFile(); Xvoid ShowFile(); Xvoid Output(); X X/** **/ X X/** some useful macros: **/ X#define max(choir,boy) (((choir)>(boy))?(choir):(boy)) X#define min(choir,boy) (((choir)<(boy))?(choir):(boy)) X X/** **/ X Xint AsciiTrace = 0; X X/* number of lines above and below each match to show by default. */ X#define DFLTABOVE 6 X#define DFLTBELOW 9 X Xint LinesBelow = DFLTBELOW; Xint LinesAbove = DFLTABOVE; X X#define DISPLAY_TOP 3 X Xextern int errno; X Xchar *progname; Xint ThisRow, ThisCol; Xint SelectedNames = -1; XFILE *InfoStream = 0; X Xstatic char *Revision = "@(#) showfile.c 2.2"; X Xint Xmain(argc, argv) X int argc; X char *argv[]; X{ X extern int optind, getopt(); X extern char *optarg; /* for getopt */ X int ch; /* for getopt */ X int ErrFlag = 0; /* see how getopt makes programs cleaner? */ X int NumberOfFiles; X char **Origv; X int Origc; X char *FileWithMatches = (char *) 0; X char **MatchList; X int MatchCount = 0; X X progname = argv[0]; X X SetDefaults(argc, argv); X X /* All lq-text programs must call SetDefaults() before getopt, and X * must then be prepared to ignore options z with arg and Z without. X */ X while ((ch = getopt(argc, argv, "a:b:f:o:z:ZVvx")) != EOF) { X switch (ch) { X case 'z': X break; /* done by SetDefaults(); */ X case 'V': X fprintf(stderr, "%s version %s\n", progname, Revision); X break; X case 'v': X AsciiTrace = 1; X break; X case 'a': /* lines above */ X LinesAbove = atoi(optarg); /* need cknum() */ X break; X case 'b': X LinesBelow = atoi(optarg); X break; X case 'f': X FileWithMatches = optarg; X break; X case 'o': /* -o fd --- write the selected files to fp */ X if (SelectedNames >= 0) { X fprintf(stderr, X "%s: -o %d -o %s: you must not give more than one -o option.\n", X progname, SelectedNames, optarg); X ErrFlag = (-1); X } else { X if (!isdigit(*optarg)) { X fprintf(stderr, "%s: -o must be followed by a number\n", X progname); X exit(1); X } X SelectedNames = atoi(optarg); X break; X } X break; X case 'x': X ErrFlag = (-1); X break; X case '?': X default: X ErrFlag = 1; X } X } X X if (ErrFlag < 0) { /* -x or -xv was used */ X fprintf(stderr, "usage: %s [-xv] [options] [matches...]\n", progname); X fprintf(stderr, X "use %s -x, -xv or -xvv for more detailed explanations.\n", progname); X X if (AsciiTrace) { X DefaultUsage(); X fprintf(stderr, "\n\ X -a above - set the number of lines shown above each matching\n\ X match to \"above\" [default is %d]\n", DFLTABOVE); X fprintf(stderr, "\ X -b below - set the number of lines shown below each match\n\ X match to \"above\" [default is %d]\n", DFLTBELOW); X fprintf(stderr, "\ X -f file -- \"file\" contains a list of matches, one per line\n"); X } X if (AsciiTrace > 1) { X fputs("\ X Matches should be in the form of\n\ X BlockNumber WordInBlock FileName\n\ X where BlockBumber and WordInBlock are positive numbers.\n\ X (This is the format produced by the lqword -l command.)\n\ X", stderr); X } X exit(0); X } else if (ErrFlag > 0) { X fprintf(stderr, "use %s -x for an explanation.\n", progname); X exit(1); X } X X /* open the file for the selected output */ X if (SelectedNames > 0) { X if ((InfoStream = fdopen(SelectedNames, "w")) == (FILE *) 0) { X int e = errno; X X fprintf(stderr, "%s: -o %d: can't open stream ", X progname, SelectedNames); X errno = e; X perror("for writing"); X exit(1); X } X } X X /* check that we can get at the file containing the matches, if one X * was supplied. X */ X if (FileWithMatches) { X struct stat StatBuf; X char *msg = 0; X X if (stat(FileWithMatches, &StatBuf) < 0) { X int e = errno; /* on many systems, fprintf() changes errno! */ X fprintf(stderr, "%s: can't open match-list file ", FileWithMatches); X errno = e; X perror(progname); X exit(1); X } else if (AsciiTrace) { X switch (StatBuf.st_mode & S_IFMT) { X case S_IFDIR: X fprintf(stderr, X "%s: ca't read matches from \"%s\" -- it's a directory!\n", X progname, FileWithMatches); X exit(1); X case S_IFREG: X break; X#ifdef S_IFIFO X case S_IFIFO: X msg = "named pipe or fifo"; X /* fall through */ X#endif X case S_IFCHR: X if (!msg) msg = "raw special device"; X /* fall through */ X case S_IFBLK: X if (!msg) msg = "block special device"; X /* fall through */ X#ifdef S_IFNAM X case S_IFNAM: X if (!msg) msg = "named special file"; /* wot dat? */ X /* fall through */ X#endif X default: X if (!msg) msg = "special file"; X X fprintf(stderr, X "%s: warning: file \"%s\" containing matches is a %s\n", X progname, FileWithMatches, msg); X X /* but continue anyway... */ X X } X } X /* Now read the file, and make an array of matches... */ X if (ReadMatchFile(FileWithMatches, StatBuf.st_size, &MatchCount, &MatchList) < 0) { X fprintf(stderr, "%s: couldn't read matches from \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X } X X argv += optind; X argc -= optind; X X if (MatchCount) { X argc = MatchCount; X argv = MatchList; X } X X if (argc < 3) { X fprintf(stderr, X "%s: matches must have at least 3 parts; use -xv for an explanation\n", X progname); X exit(1); X } else if (argc % 3) { X /* Note: I could detect lqword output here (i.e., without -l) */ X fprintf(stderr, "%s: can't understand match format;\n", progname); X fprintf(stderr, "%s: use -xv for more explanation.\n", progname); X exit(1); X } X X Origv = argv; X Origc = argc; X X ThisRow = DISPLAY_TOP - 1; X NumberOfFiles = argc / 3; X X initscr(); X nonl(); X raw(); X noecho(); X X while (argc > 0) { X char Buffer[120]; X int Where; X X ThisRow = DISPLAY_TOP; X ThisCol = (-1); X ShowFile(argv[2], atol(*argv), (unsigned) atoi(argv[1]), argc - Origc); X (void) sprintf(Buffer, "Match %d of %d", X NumberOfFiles - (argc / 3) + 1, NumberOfFiles); X Where = COLS - (strlen(Buffer) + 10); X mvwaddstr(stdscr, LINES - 1, Where, Buffer); X refresh(); /* Where (above) is in case mvwaddstr is a macro */ X X if (argc > 0) { X attrset(A_STANDOUT); X mvwaddstr(stdscr, LINES - 1, 0, "[Press SPACE to continue]"); X attrset(0); X wmove(stdscr, 0, 0); X (void) refresh(); X switch (getch()) { X case '?': X case 'x': X case 'h': X case 'i': X#ifdef KEY_HELP X case KEY_HELP: X#endif X { X WINDOW *HelpWin = newwin(12, 40, 5, (COLS - 40) / 2); X X if (HelpWin == (WINDOW *) 0) { X beep(); X } else { X#ifndef ACS_HLINE X box(HelpWin, '#', '#'); X#else X box(HelpWin, 0, 0); X /* Versions of curses with ASC_HLINE take 0 to X * mean that line-drawing should be done X * "properly". X */ X#endif X wmove(HelpWin, 1, 2); X mvwprintw(HelpWin, 1,2, "x, ? -- print this explanation"); X mvwprintw(HelpWin, 2,2, "space -- go to next match"); X mvwprintw(HelpWin, 3,2, "return -- go to next match"); X mvwprintw(HelpWin, 4,2, "0, ^, F -- go to First match"); X mvwprintw(HelpWin, 5,2, "$, L -- go to the Last match"); X mvwprintw(HelpWin, 6,2, "n, + -- go to the next file"); X mvwprintw(HelpWin, 7,2, "p, - -- go to previous file"); X mvwprintw(HelpWin, 8,2, "s, g -- save this filename"); X mvwprintw(HelpWin, 9,2, "u, d -- drop this filename"); X mvwprintw(HelpWin, 10,2, "q, Q -- quit browsing"); X wrefresh(HelpWin); X (void) getch(); X delwin(HelpWin); X#ifndef CURSESX /* This is because 4.2 BSD a brain-dead curses... */ X clearok(stdscr, TRUE); X wrefresh(stdscr); X#endif X } X } X break; X case 'q': X case 'Q': X goto AllDone; X /* the goto is to surmount an AT&T compiler bug */ X case '0': /* reset to beginning */ X case '1': X case 'f': case 'F': X case '^': case '6': /* (6 is often unshifted ^) */ X argc = Origc; X argv = Origv; X break; X case '$': /* to the end */ X case 'l': case 'L': /* Last match */ X argv += (argc - 3); X argc = 3; X break; X case 'v': /* view the file -- use PAGER */ X { X char Buffer[4096]; X char *doc; X int e = errno; X X if ((doc = FindFile(argv[2])) == (char *) 0) { X errno = e; X perror(argv[2]); X sleep(2); X goto AllDone; X } X X (void) sprintf(Buffer, "%s \"%s\"", PAGER, doc); X (void) MySystem(Buffer); X clearok(stdscr, TRUE); X wrefresh(stdscr); X } X break; X case 's': /* keep this filename for later use */ X case 'k': case 'g': /* keep, get */ X fprintf(InfoStream, "%c %s\n", 's', argv[2]); X break; /*NOTDONE*/ X case 'd': /* delete this file from the list */ X fprintf(InfoStream, "%c %s\n", 'd', argv[2]); X break; /* NOTDONE */ X case 'R': /* revert to initial state */ X break; /* NOTDONE*/ X case '-': X case 'p': X { X char *p = argv[2]; X char **Argv = argv; X int Argc = argc; X X while (Argc + 3 <= Origc && STREQ(Argv[2], p)) { X Argv -= 3; X Argc += 3; X } X X if (Argc == argc) { X beep(); X } else { X argv = Argv; X argc = Argc; X } X } X break; X case '+': X case 'n': X { X char *p = argv[2]; X char **Argv = argv; X int Argc = argc; X X while (Argc > 3 && STREQ(Argv[2], p)) { X Argv += 3; X Argc -= 3; X } X X if (Argc == argc) { X beep(); X } else { X argv = Argv; X argc = Argc; X } X } X break; X case 'R' ^ 64: /* control-R */ X case 'L' ^ 64: /* control-L */ X clearok(stdscr, TRUE); X wrefresh(stdscr); X break; X case '=': X clearok(stdscr, TRUE); X wrefresh(stdscr); X { X FILE *Pager = popen(PAGER, "w"); X char **p; X int i; X X if (!p) { X beep(); X break; X } X for (p = Origv, i = Origc; i > 0; i -= 3, p += 3) { X (void) fprintf(Pager, "%s\n", *p); X } X (void) pclose(Pager); X } X clearok(stdscr, TRUE); X wrefresh(stdscr); X break; X case ' ': X case '\r': X case '\n': X argv += 3; X argc -= 3; X break; X default: X beep(); X break; X } X } X } X XAllDone: X wmove(stdscr, LINES - 1, 0); X clrtoeol(); X /* Try to revent the screen from scrolling when we exit */ X wmove(stdscr, LINES - 2, 0); X refresh(); X endwin(); X return 0; X} X Xint XReadMatchFile(FileWithMatches, FileSize, MatchCount, MatchList) X char *FileWithMatches; X off_t FileSize; X int *MatchCount; X char ** *MatchList; X{ X extern char *strtok(); X X int fd; X char **Result; X char *StorageArea; X char *p; X unsigned int n_matches; X int BytesRead; X int i; X char *NextStr; X X if (!FileWithMatches || !*FileWithMatches) { X fprintf(stderr, "%s: match-list file (from -f) has empty name!\n", X progname); X exit(1); X } X X if ((fd = open(FileWithMatches, O_RDONLY)) == 0) { X int e = errno; X fprintf(stderr, "%s: can't open match-list file ", progname); X errno = e; X perror(FileWithMatches); X exit(1); X } X X /* We know the number of bytes, and each space or newline will get X * turned into a null, so here goes... X * The +1 below is to ensure that there is space for a \0, even if a X * pesky user didn't put a \n at * the end of the file... X * Sometimes I hate emacs... X */ X if ((StorageArea = malloc((unsigned) FileSize + 1)) == (char *) 0) { X fprintf(stderr, "%s: not enough memory to read match-list \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X X /* now read the list... */ X if ((BytesRead = read(fd, StorageArea, FileSize)) != FileSize) { X if (BytesRead < 0) { X int e = errno; X X fprintf(stderr, "%s: couldn't read %u bytes from ", X progname, FileSize); X errno = e; X perror(FileWithMatches); X exit(1); X } else { X int e = errno; X X fprintf(stderr, "%s: ", progname); X if (BytesRead > 4) { /* minimum plausible for 3 items */ X fprintf(stderr, "warning: "); X } X fprintf(stderr, "only read %u bytes, not %u, from file ", X progname, BytesRead, FileSize); X errno = e; X if (errno) perror(FileWithMatches); X else fprintf(stderr, "\"%s\"\n", FileWithMatches); X X if (BytesRead <= 4) exit(1); X X StorageArea = realloc(StorageArea, (unsigned) (BytesRead + 1)); X if (StorageArea == (char *) 0) { /* unlikely, it got smaller */ X fprintf(stderr, "%s: can't realloc for \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X FileSize = BytesRead; X } X } X X /* null-terminate it */ X StorageArea[FileSize] = '\0'; X X /* got the data, now make an array... first, count the matches */ X for (n_matches = 1, p = StorageArea; p - StorageArea < FileSize; p++) { X if isspace(*p) ++n_matches; X } X X /* If there *was* trailing new-line, we overestimated by one. X * This doesn't matter. If memory is that tight, initscr() will fail. X * In any case, allow extra space for a trailing null entry. X */ X ++n_matches; X if (n_matches < 3) n_matches = 3; X X Result = (char **) malloc((unsigned) n_matches * sizeof(char *)); X if (Result == (char **) 0) { X fprintf(stderr, "%s: out of memory reading match file \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X X /* Now step through the Storage Area filling in the pointers to the args */ X ; X X NextStr = (char *) 0; X i = -1; X for (p = StorageArea; p - StorageArea <= BytesRead; p++) { X if (!NextStr) NextStr = p; X if (isspace(*p) || p - StorageArea == BytesRead) { X if (p - StorageArea != BytesRead) *p = '\0'; X while (isspace(*p)) { /* eat multiple blanks */ X p++; X } X if (++i >= n_matches) { X n_matches += 20; X if ((Result = (char **) X realloc((char *) Result, n_matches * sizeof(char *))) == X (char **) 0) { X fprintf(stderr, X "%s: out of memory [%u] in match-file \"%s\"\n", X progname, n_matches * sizeof(char *), FileWithMatches); X /* TODO -- return with fewer matches -- NOTDONE */ X exit(1); X } X } X *p = '\0'; /* OK at the very end cos of the extra byte! */ X Result[i] = NextStr; X NextStr = (char *) 0; X } X } X X if (i + 2 < n_matches) { X Result = (char **) realloc((char *)Result, X (unsigned) (i+2) * sizeof(char **)); X if (Result == (char **) 0) { X fprintf(stderr, "%s: no memory for match-list from \"%s\"\n", X progname, FileWithMatches); X exit(1); X } X } X X if (close(fd) < 0) { X fprintf(stderr, "%s: warning: obscure problem closing %d (\"%s\")\n", X progname, fd, FileWithMatches); X sleep(5); X } X X (*MatchList) = Result; X return (*MatchCount = i); X} X Xvoid XShowFile(FileName, BlockInFile, WordInBlock, UniqueID) X char *FileName; X unsigned long BlockInFile; X unsigned int WordInBlock; X int UniqueID; X{ X static char *Buffer = 0; X int fd; X static unsigned int BufLen; X int AmountRead; X register char *p; X int LinesFound; X int InTargetWord = 0; X char *StartOfMyWord; X int ThisWord = 0; X unsigned long FirstLumpSize; X char *Start; X static int LastID = (-1); X X if (UniqueID == LastID) { X return; X } else { X LastID = UniqueID; X } X wclear(stdscr); X ThisRow = DISPLAY_TOP; X X if (Buffer == (char *) 0) { X BufLen = COLS * (LinesAbove + LinesBelow + 1) + 1; X if (BufLen < FileBlockSize * 3) BufLen = FileBlockSize * 3; X Buffer = emalloc(BufLen); X } X X errno = 0; X X if ((fd = open(FileName, O_RDONLY, 0)) < 0) { X int e = errno; X char *doc; X X if ((doc = FindFile(FileName)) == (char *) 0) { X errno = e; X perror(FileName); X sleep(2); X return; X } else if ((fd = open(doc, O_RDONLY, 0)) < 0) { X perror(doc); X sleep(2); X return; X } X FileName = doc; X } X X /* display a helpful message: */ X move(DISPLAY_TOP, 0); X clrtoeol(); X move(DISPLAY_TOP - 1, 0); X clrtoeol(); X mvwprintw(stdscr, DISPLAY_TOP - 1, 0, X "Block %lu/Word %u in document: ", BlockInFile, WordInBlock); X attrset(A_UNDERLINE); X wprintw(stdscr, "%s", FileName); X attrset(0); X X errno = 0; X if (lseek(fd, BlockInFile? (long) ((BlockInFile - 1) * FileBlockSize) : 0L, X 0) < 0) { X perror("lseek"); X sleep(2); X clearok(stdscr, TRUE); X close(fd); X return; X } X X errno = 0; X if ((AmountRead = read(fd, Buffer, BufLen)) < MinWordLength) { X perror("read"); X sleep(5); X close(fd); X clearok(stdscr, TRUE); X return; X } X X /* clear the bottom bit of screen */ X { X register int i; X X for (i = ThisRow; i < LINES; i++) { X move(i, 0); X wclrtoeol(stdscr); X } X } X X /** Find the required word */ X if (BlockInFile) { X /* start 1 char before the end of the previous block */ X StartOfMyWord = &Buffer[FileBlockSize - 1]; X /* perhaps the last word of the previous block spans the block X * boundary? X */ X while (WithinWord(*StartOfMyWord)) StartOfMyWord++; X if (StartOfMyWord < &Buffer[FileBlockSize]) { X StartOfMyWord = &Buffer[FileBlockSize]; X } X } else { X StartOfMyWord = Buffer; X } X X for (ThisWord = 0; ThisWord <= WordInBlock + 1; ThisWord++) { Xbored: X /* skip to the start of a word */ X while (!StartsWord(*StartOfMyWord)) { X ++StartOfMyWord; X } X X Start = StartOfMyWord; X X /* find the end of the word */ X while (WithinWord(*StartOfMyWord)) { X if (*StartOfMyWord == '\'' && !EndsWord(StartOfMyWord[1])) break; X StartOfMyWord++; X } X X /* Assert: StartOfMyWord points 1 character beyond the end of the X * word pointed to by Start X */ X /* see if it's long enough */ X if (StartOfMyWord - Start < MinWordLength) { X goto bored; X } X X#if 0 X /* see if it is too common */ X { X extern char *WordRoot(); X X t_WordInfo W; X register char *p, *q; X char RootBuf[MaxWordLength + 1]; X X for (p = RootBuf, q = Start; *q; p++, q++) { X if (q == StartOfMyWord) break; X *p = isupper(*q) ? tolower(*q) : *q; X } X *p = '\0'; X X W.Word = RootBuf; X W.Length = strlen(W.Word); X W.WordPlace.Flags = 0; X X (void) WordRoot(&W); X X if (TooCommon(&W)) goto bored; X X } X#endif X X /** See if it's the right one */ X if (ThisWord == WordInBlock) { X StartOfMyWord = Start; X break; X } X } X X FirstLumpSize = StartOfMyWord - Buffer; X X /* Find N lines before it */ X LinesFound = 0; X for (p = StartOfMyWord; p > Buffer; --p) { X if (*p == '\n') { X if (++LinesFound > LinesAbove) break; X } X } X X /* display them */ X while (p < StartOfMyWord) { X Output(*p); /* Output might be a macro later */ X p++; X } X X /* find N lines after it */ X X LinesFound = 0; X while (p - Buffer < AmountRead) { X switch (InTargetWord) { X case 0: X if (StartsWord(*p)) { X attrset(A_STANDOUT); X InTargetWord = 1; X } X break; X case 1: X if (!WithinWord(*p)) { X InTargetWord = 2; X attrset(0); X } X } X Output(*p); X X if (*p == '\n') { X if (++LinesFound > LinesBelow) break; X } X p++; X } X X (void) refresh(); X X (void) close(fd); X return; X} X Xvoid XOutput(ch) X int ch; X{ X switch(ch) { X default: X if (++ThisCol > COLS) { X if (++ThisRow >= LINES - 1) { X ThisRow = DISPLAY_TOP; X } X ThisCol = 0; X } X if (ThisCol <= 0) { X ThisCol = 0; X move(ThisRow, ThisCol); X clrtoeol(); X } X mvwaddch(stdscr, ThisRow, ThisCol, (chtype) ch); X break; X case '\n': X if (++ThisRow >= LINES - 1) { X ThisRow = DISPLAY_TOP; X } X ThisCol = (-1); X move(ThisRow, 0); X clrtoeol(); X break; X case '\t': X ThisCol |= 7; X break; X case ' ': X ThisCol++; X } X} X X/* X * $Log: lqshow.c,v $ X * Revision 1.9 91/03/03 00:18:26 lee X * No longer needs to check common words. X * X * Revision 1.8 90/10/06 00:50:58 lee X * Prepared for first beta release. X * X * Revision 1.7 90/10/05 23:49:25 lee X * Moved the Match %d of %d message left somewhat. X * X * Revision 1.6 90/10/03 21:26:47 lee X * Removed BSD/SYSV diffs and used CURSESX instead. X * X * Revision 1.5 90/08/29 21:45:34 lee X * Alpha release X * X * Revision 1.4 90/08/09 19:17:17 lee X * BSD lint and Saber X * X * Revision 1.3 90/07/11 10:57:46 lee X * Added limited ultrix support... also some small optimisations and X * changes to the help screen. X * X * Revision 1.2 90/04/21 16:06:24 lee X * Cleaned up the gode for gcc -W X * X * Revision 1.1 90/02/14 18:32:39 lee X * Initial revision X * X * Revision 2.1 89/10/02 01:15:51 lee X * New index format, with Block/WordInBlock/Flags/BytesSkipped info. X * X * Revision 1.3 89/09/17 23:04:04 lee X * Various fixes; NumberInBlock now a short... X * X * Revision 1.2 89/09/16 21:18:35 lee X * First demonstratable version. X * X * Revision 1.1 89/09/16 20:02:58 lee X * Initial revision X * X */ @@@End of lq-text/src/lqtext/lqshow.c echo end of part 07 -- Liam R. E. Quin, lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337