home *** CD-ROM | disk | FTP | other *** search
- From: lee@sq.sq.com (Liam R. E. Quin)
- Newsgroups: alt.sources
- Subject: lq-text Full Text Retrieval Database Part 07/13
- Message-ID: <1991Mar4.020613.16578@sq.sq.com>
- Date: 4 Mar 91 02:06:13 GMT
-
- : 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
-