home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / fileutil / scan.lha / src / scan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-21  |  115.1 KB  |  2,615 lines

  1.  
  2. /* Copyright © 1991, 1992 by Walter Rothe. You may freely use and modify this
  3.  * program, but not for commercial profit. A modest fee for distribution is
  4.  * allowed. Derivative works must be released with source along with the
  5.  * executable or provisions made to provide the user source, if requested.
  6.  * Uploading source to a major bulletin board system within 6 months of the
  7.  * time of the request satisfies this requirement. This copyright notice
  8.  * must not be deleted from the source.
  9.  */
  10.  
  11. /*                                                                           */
  12. /*                                  Scan                                     */
  13. /*                                                                           */
  14. /* This program scans file(s) looking for a pattern(s). It supports many     */
  15. /* wildcard characters in patterns(*,?,[],[^],[-],&,..,+,|) and can scan     */
  16. /* for up to 125 patterns simultaneously with little speed degradation.      */
  17. /* If a match is found, a whole article can be printed out instead of just   */
  18. /* a number of lines around the match. It also supports recursive directory  */
  19. /* scanning and inverted pattern matching.                                   */
  20. /*                                                                           */
  21. /* Limitations: 1. Total file pathname must be less than LONGWIDTH wide.     */
  22. /*                 Aborts otherwise.                                         */
  23. /*              2. Article separator must be less than MAXKWSZ and LWIDTH    */
  24. /*                 characters long. Aborts otherwise.                        */
  25. /*              3. Sentence scan only looks OVERLAP chars to left or right   */
  26. /*                 of keyword match to see if rest of stuff matches.         */
  27. /*              4. Patterns are a max of LWIDTH chars wide. If not, it       */
  28. /*                 aborts.                                                   */
  29. /*              5. A max of 125 major terms is supported. Aborts otherwise.  */
  30. /*              6. A major term must have at least 1 set of 2 consequtive    */
  31. /*                 non wildcard characters. Otherwise, it will abort.        */
  32. /*              7. Article separator must be at least 2 chars long and have  */
  33. /*                 at least 2 unique chars. Otherwise, it will abort.        */
  34. /*              8. If article size is > window size(buffer size), there      */
  35. /*                 is a chance that not all of it will be printed out. A     */
  36. /*                 warning will be printed out if this occurs. At least one  */
  37. /*                 buffers worth will always be printed out. The part of the */
  38. /*                 article in the current buffer will also be printed out.   */
  39. /*              9. The ".." wildcard causes a match on either the left or    */
  40. /*                 right MT if the LineScan option is set.                   */
  41. /*              10.Buffer size must be in longword increments.               */
  42. /*                                                                           */
  43. #include <stdio.h>
  44. #include <exec/types.h>
  45. #include <exec/memory.h>
  46. #include <libraries/dos.h>
  47. #include <libraries/dosextens.h>
  48. #include <functions.h>
  49. #include "fcntl.h"
  50. #include "ctype.h"
  51. #include <string.h>
  52. #include "scan.h"
  53. #include <time.h>
  54.  
  55. #ifndef LATTICE
  56. #endif
  57.  
  58. clock_t StrtTime;
  59. clock_t EndTime;
  60. clock_t TotTime=0;
  61.  
  62. extern FastSearch();             /* Inner loop search(returns maj term #)    */
  63.  
  64. extern Lines *GetMajTrms();      /* Get list of Maj Trms from Min Terms      */
  65.  
  66. extern int NumOfMinTrms;
  67. extern int NumOfMajTrms;
  68.  
  69. extern XFI *xfropen();
  70. extern long xfrread();
  71. extern xfrclose();
  72. extern FindRestOfMT();
  73. extern struct Library *OpenLibrary();
  74.  
  75. char SubPat[65536];              /* Major term index from two char index     */
  76. unsigned short CurPat;
  77. unsigned short SavEPat, SavTEPat;
  78. unsigned short SavOPat, SavTOPat;
  79. unsigned short frstuppr, scnduppr;
  80. /* "rest of" signifies the characters remaining after the 2 char subkey is   */
  81. /* removed. Lets say the keyword is "never" and the subkey is "ne". In this  */
  82. /* case, the rest is "ver". If the subkey was "ev", the rest is "never",     */
  83. /* since it doesn't do separate compares. If the keyword is "ab" then the    */
  84. /* subkey is also "ab" and the rest is "ab". We need at least 2 chars since  */
  85. /* tables FrstBt and ScndBt are used, without testing 4 finished, for speed  */
  86. unsigned char DsplTb[2*MAXMTS]; /* Displ 2 1st char of rest of key from MTIdx*/
  87. char FrstBt[2*MAXMTS];    /* 1st char of rest of keyword from maj term index */
  88. char ScndBt[2*MAXMTS];    /* 2nd char of rest of keyword from maj term index */
  89. char LowrCs[256];                /* Lower case char from mixed case chars    */
  90. int  MajTrm2MinTrm[MAXMTS];      /* Minterm number indexed by major term num */
  91. int  MajTrm2BitNum[MAXMTS];      /* Bit number in MinSatTbl from maj trm #   */
  92. int  MinSatByMTOnly[MAXMTS];     /* 1 if min term is satisfied by 1 maj trm  */
  93. int  MajTrm2MaxKeyLen[MAXMTS];   /* Length of longest keyword in major term  */
  94. int  MTNumSortedByKeyLen[MAXMTS];/* Maj Trm #'s sorted by length of keyword  */
  95. char *FreeItList[256];           /* Max number of bracket expressions        */
  96. int  FrI=0;
  97. int  NextMT;
  98. int  PrntPrevPrev = 0;
  99. int  CurLen;
  100. int  TokLen;
  101. int  CurDirModified=0;
  102. int  LineScan;
  103. int  LineNum = 0;                /* Print out line number with match if 1    */
  104. int  TermLp = 0;
  105. int  NumDup;
  106. int  FrstPnt;
  107. int  LastInLast;           /* zero if nothing printed out in present buf yet */
  108. int  PrntWidth=0;
  109. int  AlwaysPrint = 0;            /* if 1, always print file pathname scanned */
  110. int  LenSt;
  111. int  SzPtr;
  112. int  WroteOverIt = 0;
  113. int  Inv;
  114. int  DKWIdx;
  115. int  SavEIdx, SavTEIdx;
  116. int  SavOIdx, SavTOIdx;
  117. int  NumBefore=0, NumAfter=1;
  118. int  RealFile;            /* if 1, outputting to real file instead of screen */
  119. int  InvertMatch=0;              /* When 1, outputs articles that dont match */
  120. int  ColReq=0;      /* Column that article separator must be in. 0 -> ignore */
  121. int  ColOk;
  122. int  FDsplTbl[MAXDUP];           /* Full Displ to strt of keywrd by MT Index */
  123. int  ArtInPrevBuf;               /* Start of article is in previous buffer   */
  124. int  BlkSize=1;                  /* Size of block to write to output stream  */
  125. long NumBlksToWrt;               /* Num of blocks to write to output stream  */
  126. long NumBlksToWrt2;
  127. char *WhereToStrt;               /* Pntr 2 start of article to write out     */
  128. char *EndOfPrevBuf;              /* Pntr 2 end of buffer used b4 current buf */
  129. char *iii;
  130. int  bufchr;
  131. char *SOCB;                      /* Pntr 2 start of current buf being used   */
  132. char *ASOB;                      /* Pntr 2 absolute start of current buffer  */
  133. long CurOddOH;
  134. long CurEvenOH;
  135. long TotOH;
  136. long MulFct;
  137. long OH;
  138. char *KWTbl[2*MAXMTS][2];        /* Pntrs 2 1st & last char of rest of keywd */
  139. char *SvTbl[2*MAXMTS];           /* Saves pntr to strt of keyword for later  */
  140. char *DKWTbl[MAXDUP][4]; /* Pntrs 2 1st/last/Dspl/link 2 next dup 4 rest kwd */
  141. char *EOCB;                      /* Pntr 2 end last byte in current buf + 1  */
  142. char *SavEOCB, *SavSOCB;
  143. char **TmpPtr;
  144. char ArticleSep[] = "\nArticle";
  145. char *ArtSep = ArticleSep;       /* Pntr 2 rest of article separator         */
  146. char *EOASep = ArticleSep + 7;   /* Pntr 2 last char of rest of article sep  */
  147. unsigned char DFASep[2];         /* Displ for art sep into buffer            */
  148. char *CurArtStrt;                /* Pntr 2 strt of article in a buffer       */
  149. char EOBK[] = "$-$";             /* Keyword indicating end of buffer         */
  150. char LineSrchDelim[] = "%!%";    /* Article separator when doing line search */
  151. char *PntPtr;
  152. char *RightStrt;
  153. char *LastPntEnd;
  154. long WinSiz = 16384;             /* Size in bytes of each of the 3 buffers   */
  155. FILE *StrmPtr = stdout;          /* Output stream                            */
  156. FILE *OutFile=NULL;              /* Output file                              */
  157. FILE *ConfigF=NULL;              /* Configuration file                       */
  158. char ArtBuf[LWIDTH];             /* Buffer to put article separator in       */
  159. Lines MinArray[MAXMTS];
  160. Lines *MinTerm = &MinArray[0];
  161. Lines *EndMin;
  162. Lines *MinPtr;
  163. long MinSatTbl[MAXMTS][2];       /* 32 bit fields & masks of MT's satisfied  */
  164. int LastMTTbl[MAXMTS];           /* Daisy chain of major terms found in art  */
  165. int MTIndx;
  166. int LastMT;                      /* Index into LastMTTbl of last maj trm fnd */
  167. Lines Garb1;
  168. char *Stf1 = (char *)&Garb1;
  169. Lines Garb2;
  170. char *Stf2 = (char *)&Garb2;
  171. Lines Garb3;
  172. char *Stf3 = (char *)&Garb3;
  173. char *TmpTrm;
  174. Lines MTArray[MAXMTS];
  175. Lines NoBrakArray[MAXMTS];    /* Array of MT's with stuff between [] removed */
  176.                               /* Also ] is removed. This array winds up      */
  177.                               /* having the *,&, and [ chars changed to zero */
  178. Lines NoBrakAry[MAXMTS];      /* Same as NoBrakArray except the *,&, and [   */
  179.                               /* are not overwritten with 0.                 */
  180. int TokStrt[2*MAXMTS];
  181. int TokEnd[2*MAXMTS];
  182. char *NBAryEnd[MAXMTS];       /* pntrs to end of MT strings with no ]        */
  183. Lines *MajTerm = &MTArray[0];
  184. Lines *LstMajTrm;
  185. Lines *EndMT;
  186. char *InName, *OutName, *LastArg;
  187. char *Tok, *SavTok, *SavTTok;
  188. DIB *CurDirPtr=NULL;
  189. int i, j, k, ll, ci, t1;      /* counter variables */
  190. int FndBrak;
  191. int StrtBrk;
  192. BrakTyp1 *BrakIdx=NULL;
  193. BrakTyp2 *BrakPtr=NULL;
  194. char *myptr;
  195. int FndALOGKeyWrd;
  196. int OutArt = 0;
  197. int Indx;
  198. int LFCnt;
  199. int Mtch1st = 0;
  200. int MatchFnd=1;
  201. int MatchNotFnd=0;
  202. XFI *FHandle=0;
  203. char *FName;
  204. char *TmpCS, *TmpCS2;
  205. long ReadNum;
  206. char *malloc(), *strcpy(), *strcat();
  207. int HasCnfgF;
  208. unsigned char MTNum;                   /* Major term number.                 */
  209. unsigned char MTN;                     /* Major term index. MTN = MTIdx>>1   */
  210. unsigned char MTIdx;                   /* Major term index. MTNum = MTIdx>>1 */
  211. char **MTTmp;
  212. char *BufIdx;
  213. char *TmpP, *BP;
  214. int CmdLnArgIdx, LstCmdLnArgIdx, RecursFlg = 0;
  215. int NumOfCR = 0;     /* Num of line feeds in all buffs already scanned    */
  216. int NumOfCRInCurBuf = 0; /* Num of line feeds found so far in current buf */
  217. char *LstOut = NULL; /* Pntr to last char outputed in current buffer + 1  */
  218. long NumTot=-1;
  219. static int LnSz;
  220. int Trunc=0;
  221. int TextWidth;       /* Width of current window in characters */
  222. int HasKeyWrd=1;
  223. int NoKeyW=0;
  224. char *HighLightColor="\x9B\x33\x32m";
  225. char *PathNmColor="\x9B\x33\x33m";
  226. char *DlydPntStart=NULL; /* Pntr 2 right context that still needs 2b printed */
  227. int   DlydPntRightContext=0;
  228. long  DlydPntSize=0;
  229. int   DlydPntNextBuf=0;
  230. char *KeyStrt;
  231. char *WrdStrt;
  232. char *DlydPntEnd;
  233. int SizeDiff;
  234. int TotTokLen;
  235. int KeyWrdOvlp = MAXKWSZ;  /* Used in asyncread.c for main srch buf overlap */
  236. int OpenNew = 0;            /* 1 if finished with internal LZH archive file */
  237. int LON;
  238. int StrtLFC;
  239. char *StrtPP;
  240. int  CutIt = 0; /* binary file cut since could not find a line feed in time */
  241. int  MayNeedLF = 0;
  242. char *LZHFileName = "";      /* Internal filename of lzh file being scanned */
  243. char *WildLZH = "*";   /* Wildcard pattern of which lzh int files to search */
  244. int EnableLZHDecomp = 0;  /* When true, enables decompression of .lzh files */
  245. int TwoCharArtSep = 0; /* If 1, the article separator is only 2 chars long. */
  246. int SPIdx;
  247. int iij;
  248. int FndX;
  249. int TmpT;
  250. long ZeroLong=0;
  251. extern int ItsALZH;
  252. FILE *zero=NULL;
  253.  
  254.  
  255. void ClrSubPat()
  256. /* This should be done in assembly */
  257. {
  258.    long i;
  259.    for (i=0; i<65536; i++) { SubPat[i] = 0; }
  260. }
  261.  
  262. int MaxVal(a, b)
  263. int *a, *b;
  264. {
  265.    if (MajTrm2MaxKeyLen[*a] < MajTrm2MaxKeyLen[*b]) { return(-1);  }
  266.    else     { return( MajTrm2MaxKeyLen[*a] > MajTrm2MaxKeyLen[*b]); }
  267. }
  268.  
  269. int WindowSize()
  270. {
  271.   char c;
  272.   int n = 0, width;
  273.   char buffer[32];
  274.  
  275.   set_raw();
  276.   printf("\2330 q"); /* get window bounds */
  277.   n = 0;
  278.   while( (buffer[n] = getchar()) != 'r' && n++ < 32);
  279.   c = buffer[n-3];
  280.   width = ( (c <= '9' && c > '0') ? (c - '0') * 10 : 0 )
  281.           + buffer[n-2] - '0';
  282.   buffer[n-1] = '\0';
  283.   set_con();
  284.   return(width);
  285. }
  286.  
  287. void fxwrite( Buf, BlkSiz, Count, Strm, KeyWrdPrs )
  288. /* if "line number" option selected, output line number with output text, */
  289. /* otherwise just output text. fx is called for present buf, fy for prev. */
  290. /* Note that at each buffer switch, the number of line feeds in the prev  */
  291. /* buffer is added to the previous total(NumOfCR). Also truncate lines    */
  292. /* that are wider than window, if -t option set. Change color of word     */
  293. /* containing the matched keyword so it's highlighted.                    */
  294.  
  295. char *Buf;
  296. size_t BlkSiz, Count;
  297. FILE *Strm;
  298. int KeyWrdPrs;    /* set by caller if keyword is present at end of buffer */
  299. {
  300.    long NumBytInRec;
  301.    int OnSameLine=0;
  302.    static int ColorOn=0;
  303.    int ColorEnable=0;
  304.    int DfSz;
  305.    char *SavLO;
  306.    int TurnColorOff=0;
  307.    int MinBefore; /* min # of chars before keyword needing color highlight   */
  308.  
  309.    if (!RealFile) {
  310.       /* set all nonprinting chars to blanks */
  311.       for (iii=Buf; iii<Buf+Count; iii++) {
  312.          bufchr = (int)(*iii);
  313.          if( ( !(*iii > 32 || (*iii < 0 && *iii > -97)) && *iii != '\n')
  314.             || *iii == 0x7E) *iii = ' ';
  315.       }
  316.    }
  317.  
  318.    if( LineNum ) {
  319.       if( Count == 0) return;
  320.       if( Buf < SOCB ) { ErrP("Error: program bug!!! Buf < SOCB \n"); }
  321.       if( Buf > EOCB ) { ErrP("Error: program bug!!! Buf > EOCB \n"); }
  322.       if( LstOut < SOCB ) { ErrP("Error: LstOut < SOCB \n"); }
  323.       if( LstOut > EOCB ) { ErrP("Error: LstOut > EOCB \n"); }
  324.       /* count line feeds from last output to start of current output */
  325.       CntCRInCurBuf( Buf);
  326.       if( NumTot == NumOfCR + NumOfCRInCurBuf ) OnSameLine = 1;
  327.       while( Count != 0 ) {
  328.          SavLO = LstOut;
  329.          if( ColorOn && OnSameLine ) {
  330.             while( Count != 0 && isalnum((int)(*LstOut))){ LstOut++; Count--; }
  331.             fprintf( Strm, HighLightColor );
  332.             if( Count != 0) TurnColorOff = 1;
  333.          }
  334.          else {
  335.             while( Count != 0 && *LstOut != '\n') { LstOut++; Count--; }
  336.          }
  337.          NumTot = NumOfCR + NumOfCRInCurBuf;
  338.          if( Count != 0 && *LstOut == '\n') {
  339.             NumOfCRInCurBuf++;
  340.             LstOut++;
  341.             Count--;
  342.          }
  343.          if( ColorEnable && (!Trunc || LnSz <= TextWidth) ) {
  344.             ColorEnable = 0;
  345.             ColorOn = 1;
  346.             OnSameLine = 1;
  347.             fprintf( Strm, HighLightColor );
  348.          }
  349.          if( KeyWrdPrs && Count == 0 && !ColorOn && !RealFile) {
  350.             MinBefore = TotTokLen;
  351.             while( (isalnum((int)(*(LstOut-1))) || MinBefore > 0)
  352.                                               && LstOut != SavLO) {
  353.                Count++;
  354.                LstOut--;
  355.                MinBefore--;
  356.             }
  357.             ColorEnable = 1;
  358.          }
  359.          /* if last time we printed a match, we were on the same line as  */
  360.          /* current match, don't put out line #.                          */
  361.          if( !OnSameLine ) {
  362.             if( NumTot > 99999 ) {
  363.                if( Trunc ) { /* truncate line if line is too long */
  364.                   DfSz = LstOut - SavLO;
  365.                   LnSz = DfSz + 8; /* size of data plus size of line # */
  366.                   if( LnSz > TextWidth ) { LnSz = TextWidth; DfSz = LnSz - 8; }
  367.                   if( LnSz >= TextWidth && ColorEnable ) {
  368.                      fprintf( Strm, HighLightColor );
  369.                   }
  370.                   fprintf( Strm, "%7ld ", NumTot+1 );
  371.                   if( LnSz >= TextWidth && ColorEnable ) {
  372.                      fprintf( Strm, "\2330m");
  373.                   }
  374.                   fwrite( SavLO, BlkSiz, DfSz, Strm );
  375.                }
  376.                else {
  377.                   fprintf( Strm, "%7ld ", NumTot+1 );
  378.                   fwrite( SavLO, BlkSiz, LstOut - SavLO, Strm );
  379.                }
  380.             }
  381.             else {
  382.                if( Trunc ) {
  383.                   DfSz = LstOut - SavLO;
  384.                   LnSz = DfSz + 6;
  385.                   if( LnSz > TextWidth ) { LnSz = TextWidth; DfSz = LnSz - 6; }
  386.                   if( LnSz >= TextWidth && ColorEnable ) {
  387.                      fprintf( Strm, HighLightColor );
  388.                   }
  389.                   fprintf( Strm, "%5ld ", NumTot+1 );
  390.                   if( LnSz >= TextWidth && ColorEnable ) {
  391.                      fprintf( Strm, "\2330m");
  392.                   }
  393.                   fwrite( SavLO, BlkSiz, DfSz, Strm );
  394.                }
  395.                else {
  396.                   fprintf( Strm, "%5ld ", NumTot+1 );
  397.                   fwrite( SavLO, BlkSiz, LstOut - SavLO, Strm );
  398.                }
  399.             }
  400.             OnSameLine = 0;
  401.          }
  402.          else {
  403.             if( Trunc ) {
  404.                DfSz = LstOut - SavLO;
  405.                if( DfSz + LnSz > TextWidth ) {
  406.                   DfSz = TextWidth - LnSz;
  407.                   LnSz = TextWidth;
  408.                }
  409.                else { LnSz += DfSz; }
  410.                fwrite( SavLO, BlkSiz, DfSz, Strm );
  411.             }
  412.             else {
  413.                fwrite( SavLO, BlkSiz, LstOut - SavLO, Strm );
  414.             }
  415.             OnSameLine = 0;
  416.             if( ColorOn ) {
  417.                fprintf( Strm, "\2330m");
  418.                if( *(LstOut-1) == '\n' ) {
  419.                   ColorOn = 0;
  420.                }
  421.                else {
  422.                   if( TurnColorOff ) OnSameLine = 1;
  423.                }
  424.                if( TurnColorOff ) { TurnColorOff = 0; ColorOn = 0; }
  425.             }
  426.          }
  427.       }
  428.    }
  429.    else { /* no line numbers */
  430.       SavLO = Buf;
  431.       if( ColorOn ) {
  432.          /* Change color of the part of matched keyword to the right of     */
  433.          /* the two char subpat up to the 1st space or line feed.           */
  434.          LstOut = Buf;
  435.          while( Count != 0 && isalnum((int)(*LstOut)) ) {
  436.             LstOut++;
  437.             Count--;
  438.          }
  439.          fprintf( Strm, HighLightColor );
  440.          fwrite( SavLO, BlkSiz, LstOut - SavLO, Strm );
  441.          SavLO = LstOut;
  442.          LstOut += Count;
  443.          fprintf( Strm, "\2330m");
  444.          if( Count != 0) ColorOn = 0;
  445.       }
  446.       else {
  447.          LstOut = SavLO + Count;
  448.       }
  449.       if( KeyWrdPrs && !RealFile) {
  450.          /* Change color of the part of matched keyword to the left of and  */
  451.          /* including the two char subpat. Stop moving left on space or     */
  452.          /* start of buffer. Note that when this routine is called with     */
  453.          /* KeyWrdPrs set, the two char subpat is always the last item in   */
  454.          /* the buffer. The left context is before it.                      */
  455.          Count = 0;
  456.          MinBefore = TotTokLen;
  457.          while( (isalnum((int)(*(LstOut-1))) || MinBefore > 0)
  458.                                     && LstOut != SavLO) {
  459.             Count++;
  460.             LstOut--;
  461.             MinBefore--;
  462.          }
  463.          fwrite( SavLO, BlkSiz, LstOut - SavLO, Strm );
  464.          fprintf( Strm, HighLightColor );
  465.          SavLO = LstOut;
  466.          LstOut += Count;
  467.          fwrite( SavLO, BlkSiz, LstOut - SavLO, Strm );
  468.          fprintf( Strm, "\2330m");
  469.          if( *(LstOut-1) != '\n' ) ColorOn = 1;
  470.       }
  471.       else {
  472.          fwrite( SavLO, BlkSiz, LstOut - SavLO, Strm );
  473.       }
  474.    }
  475.    if( CutIt ) { if( LnSz != TextWidth) fprintf( Strm, "\n"); CutIt = 0; }
  476.    fflush( Strm );
  477.    return;
  478. }
  479.  
  480. void fywrite( Buf, BlkSiz, Count, Strm )
  481. /* if "line number" option selected, output line number with output text */
  482. /* otherwise just output text. fy is called for prev buf, fx for present */
  483. char *Buf;
  484. size_t BlkSiz, Count;
  485. FILE *Strm;
  486. {
  487.    char *CurPtr;
  488.    int OnSameLine=0;
  489.    long NumCR2EndOfPBuf=0;
  490.    char *SavLO;
  491.    int DfSz;
  492.    if (!RealFile) {
  493.       /* set all nonprinting chars to blanks */
  494.       for (iii=Buf; iii<Buf+Count; iii++) {
  495.          bufchr = (int)(*iii);
  496.          if( ( !(*iii > 32 || (*iii < 0 && *iii > -97)) && *iii != '\n')
  497.             || *iii == 0x7E) *iii = ' ';
  498.       }
  499.    }
  500.    if( LineNum ) {
  501.       if( Buf < SavSOCB ) { ErrP("Error: program bug!!! Buf < Prev SOCB \n"); }
  502.       if( Buf > SavEOCB ) { ErrP("Error: program bug!!! Buf > Prev EOCB \n"); }
  503.       if( Count == 0 ) { ErrP("Error2: Count to fywrite = 0 \n"); }
  504.       if( LstOut < SOCB ) { ErrP("Error2: LstOut < SOCB \n"); }
  505.       if( LstOut > EOCB ) { ErrP("Error2: LstOut > EOCB \n"); }
  506.       /* count line feeds from start of output in prev buf 2 end of prev buf */
  507.       CurPtr = SavEOCB;
  508.       for(; CurPtr>=Buf; CurPtr-- ) { if( *CurPtr == '\n') NumCR2EndOfPBuf++; }
  509.       CurPtr++;
  510.       if( NumTot == NumOfCR - NumCR2EndOfPBuf ) OnSameLine = 1;
  511.       while( Count != 0 ) {
  512.          SavLO = CurPtr;
  513.          while( (--Count != 0) && (*CurPtr != '\n') ) { CurPtr++; }
  514.          NumTot = NumOfCR - NumCR2EndOfPBuf;
  515.          if( *CurPtr != '\n') NumCR2EndOfPBuf--;
  516.          CurPtr++;
  517.          /* if last time we printed a match, we were on the same line as  */
  518.          /* current match, don't put out line #.                          */
  519.          if( !OnSameLine ) {
  520.             if( NumTot > 99999 ) {
  521.                fprintf( Strm, "%7ld ", NumTot+1 );
  522.                if( Trunc ) { /* truncate line if line is too long */
  523.                   DfSz = CurPtr - SavLO;
  524.                   LnSz = DfSz + 8; /* size of data plus size of line # */
  525.                   if( LnSz > TextWidth ) { LnSz = TextWidth; DfSz = LnSz - 8; }
  526.                   fwrite( SavLO, BlkSiz, DfSz, Strm );
  527.                }
  528.                else {
  529.                   fwrite( SavLO, BlkSiz, CurPtr - SavLO, Strm );
  530.                }
  531.             }
  532.             else {
  533.                fprintf( Strm, "%5ld ", NumTot+1 );
  534.                if( Trunc ) {
  535.                   DfSz = CurPtr - SavLO;
  536.                   LnSz = DfSz + 6;
  537.                   if( LnSz > TextWidth ) { LnSz = TextWidth; DfSz = LnSz - 6; }
  538.                   fwrite( SavLO, BlkSiz, DfSz, Strm );
  539.                }
  540.                else {
  541.                   fwrite( SavLO, BlkSiz, CurPtr - SavLO, Strm );
  542.                }
  543.             }
  544.             OnSameLine = 0;
  545.          }
  546.          else {
  547.             if( Trunc ) {
  548.                DfSz = CurPtr - SavLO;
  549.                if( DfSz + LnSz > TextWidth ) {
  550.                   DfSz = TextWidth - LnSz;
  551.                   LnSz = 0;
  552.                }
  553.                else { LnSz += DfSz; }
  554.                fwrite( SavLO, BlkSiz, DfSz, Strm );
  555.             }
  556.             else {
  557.                fwrite( SavLO, BlkSiz, CurPtr - SavLO, Strm );
  558.             }
  559.             OnSameLine = 0;
  560.          }
  561.       }
  562.       NumTot = NumOfCR;
  563.    }
  564.    else {
  565.       fwrite( Buf, BlkSiz, Count, Strm );
  566.    };
  567.    if( CutIt ) { if( LnSz != TextWidth) fprintf( Strm, "\n"); CutIt = 0; }
  568.    return;
  569. }
  570.  
  571. void _abort()
  572. {
  573.    CleanIt();
  574.    abort();
  575.    Exit(2);
  576. }
  577.  
  578. BackSlash(str)
  579.    char *str;
  580. {
  581.    /* Converts string pointed to by str that contains backslashes to a      */
  582.    /* string without backslashes.                                           */
  583.    int i = 0, k = 0, t, c;
  584.    char *subst = "000";
  585.    while( str[i]) {
  586.       if( str[i] == '\\') {
  587.          switch( str[++i] ) {
  588.             case('a'): str[i] = '\a'; break;
  589.             case('b'): str[i] = '\b'; break;
  590.             case('f'): str[i] = '\f'; break;
  591.             case('n'): str[i] = '\n'; break;
  592.             case('r'): str[i] = '\r'; break;
  593.             case('t'): str[i] = '\t'; break;
  594.             case('v'): str[i] = '\v'; break;
  595.             case('"'): str[i] = '\"'; break;
  596.             case('\''): str[i] = '\''; break;
  597.             case('\\'): str[i] = '\\'; break;
  598.             case('x'):
  599.             case('X'):
  600.                sscanf(&str[i+1], "%x", &t);
  601.                c = t;
  602.                if(( t > 0) && ( t < 256)) {
  603.                   while( t > 0) { i++; t = t >> 4; }
  604.                   str[i] = (char)c;
  605.                }
  606.                else { ErrP("Error: only 2 hex digit allowed after \\x \n"); }
  607.                break;
  608.             case('0'): case('1'): case('2'): case('3'): case('4'):
  609.             case('5'): case('6'): case('7'): case('8'): case('9'):
  610.                subst[0] = str[i];
  611.                for(c=1; (str[++i] >= '0') && (str[i] <= '9') && (c < 3); c++) {
  612.                   subst[c] = str[i];
  613.                }
  614.                subst[c] = '\0';
  615.                if( (t = atoi( subst)) < 256) { str[--i] = (char)t; }
  616.                else { ErrP("Error: decimal # after \\ must be < 256\n"); }
  617.                break;
  618.             default: ErrP("Error: illegal character after backslash\n");
  619.          }
  620.       }
  621.       str[k++] = str[i++];
  622.    }
  623.    str[k] = '\0';
  624. }
  625.  
  626. CleanIt()
  627. {
  628.    BPTR TLock;
  629.    DIB *TempPtr;
  630. #ifdef DEBUGCLEAN
  631.    printf("1st statement in cleanit\n");
  632.    fflush( zero );
  633. #endif
  634.    /* pop up any dir levels and restore original current directory */
  635.    while ( CurDirPtr != NULL ) {
  636.       if (CurDirPtr->CurLock != 0 ) {
  637.          UnLock( CurDirPtr->CurLock );
  638. #ifdef DEBUGCLEAN
  639.          printf("unlocked\n");
  640.          fflush( zero );
  641. #endif
  642.       }
  643.       if (CurDirPtr->OldLock != 0 ) {
  644.          TLock = CurrentDir( CurDirPtr->OldLock );
  645. #ifdef DEBUGCLEAN
  646.          printf("set currentdir\n");
  647.          fflush( zero );
  648. #endif
  649.       }
  650.       if (CurDirPtr->BackLink != NULL) {
  651.          TempPtr = CurDirPtr->BackLink;
  652.          FreeMem( CurDirPtr, ( long ) sizeof ( struct DirInfoBlock ) );
  653.          CurDirPtr = TempPtr;
  654. #ifdef DEBUGCLEAN
  655.          printf("freed what CurDirPtr points to\n");
  656.          fflush( zero );
  657. #endif
  658.       }
  659.       else {
  660.          FreeMem( CurDirPtr, ( long ) sizeof ( struct DirInfoBlock ) );
  661.          CurDirPtr = NULL;
  662. #ifdef DEBUGCLEAN
  663.          printf("last free of what CurDirPtr points to\n");
  664.          fflush( zero );
  665. #endif
  666.       }
  667.    }
  668.    xfrclose( FHandle);
  669.    NumOfCR = 0;
  670.    if( ConfigF != NULL ) { fclose( ConfigF ); ConfigF = 0; }
  671.    if( OutFile != NULL ) { fclose( OutFile ); OutFile = 0; }
  672.    if( BrakIdx != NULL ) {
  673.       FreeMem( BrakIdx, (long)(MAXMTS*sizeof(BrakTyp1)));
  674.       BrakIdx = 0;
  675. #ifdef DEBUGCLEAN
  676.       printf("freed mem for braketidx\n");
  677.       fflush( zero );
  678. #endif
  679.    }
  680.    if( BrakPtr != NULL ) {
  681.       FreeMem( BrakPtr, (long)(MAXMTS*sizeof(BrakTyp2)));
  682.       BrakPtr = 0;
  683. #ifdef DEBUGCLEAN
  684.       printf("freed mem for braketptr\n");
  685.       fflush( zero );
  686. #endif
  687.    }
  688.    while( FrI > 0 ) FreeMem( FreeItList[--FrI], 256 );
  689. }
  690.  
  691. /* Normal strncpy with NULL added if n < length of s */
  692. char *mystrncpy(d, s, n)
  693. char *d;
  694. const char *s;
  695. size_t n;
  696.  
  697. {
  698.    char c;
  699.    char *t = d;
  700.  
  701.    while(n && (c = *s)) { *d = c; ++s; ++d; --n; }
  702.    if( n) { *d = 0; } else { if( d-- > t) *d = 0; }
  703.    return(t);
  704. }
  705.  
  706. ErrP(msg)
  707. char *msg;
  708. {
  709.    fprintf(stderr,msg);
  710.    CleanIt();
  711.    exit(1);
  712. }
  713.  
  714. PathPrint(Matched)
  715. /* Print pathname of file being searched. "AlwaysPrint" signifies that the */
  716. /* pathname should be printed even if a match is not found in a file. If   */
  717. /* a match is not found in a file, it's pathname is overwritten by the     */
  718. /* next file scanned. When doing screen output, the color of the pathname  */
  719. /* printed is changed.                                                     */
  720. int Matched;
  721. {
  722.    static unsigned long BlkSz = 1;
  723.    static unsigned long Wrt1 = 1;
  724.    static unsigned long Wrt2 = 2;
  725.    static unsigned long Wrt9 = 9;
  726.    static char LastFileNm[LONGWIDTH] = "\0";
  727.    LLines TempFN;
  728.    extern int Mtch1st; /* flag set after 1st match in a file */
  729.    int pad;
  730.    strcpy( TempFN, FName);
  731.    if( ItsALZH ) {
  732.       strcat( TempFN, "(" );
  733.       strcat( TempFN, LZHFileName );
  734.       strcat( TempFN, ")" );
  735.    }
  736.    if(Matched) { /* a match was found before this routine was called */
  737.       if(RealFile) {
  738.          if(strcmp(LastFileNm, TempFN)) { /* not = so havent printed it yet */
  739.             fwrite("->>>>>>> ",BlkSz,Wrt9,StrmPtr);
  740.             fwrite(TempFN,BlkSz,strlen(TempFN),StrmPtr);
  741.             fwrite("\n",BlkSz,Wrt1,StrmPtr);
  742.             strcpy(LastFileNm, TempFN);
  743.             Mtch1st = 1;
  744.          }
  745.          else {
  746.             if(!Mtch1st) { fwrite("\n",BlkSz,Wrt1,StrmPtr); Mtch1st = 1; }
  747.          }
  748.       }
  749.       else {
  750.          if(strcmp(LastFileNm, TempFN)) { /* not = so havent printed it yet */
  751.             printf(PathNmColor);
  752.             fwrite(TempFN,BlkSz,strlen(TempFN),StrmPtr);
  753.             fwrite("\n",BlkSz,Wrt1,StrmPtr);
  754.             printf("\2330m");
  755.             strcpy(LastFileNm, TempFN);
  756.             Mtch1st = 1;
  757.          }
  758.          else {
  759.             if(!Mtch1st) { fwrite("\n",BlkSz,Wrt1,StrmPtr); Mtch1st = 1; }
  760.          }
  761.       }
  762.    }
  763.    else {
  764.       if(!RealFile && AlwaysPrint) {
  765.          if(strcmp(LastFileNm, TempFN)) { /* not = so havent printed it yet */
  766.             fwrite("\r",BlkSz,Wrt1,StrmPtr);
  767.             printf(PathNmColor);
  768.             fwrite(TempFN,BlkSz,strlen(TempFN),StrmPtr);
  769.             printf("\2330m");
  770.             pad = strlen(TempFN) - strlen(LastFileNm);
  771.             while (pad < 0) { fputs(" ",StrmPtr); pad++; }
  772.             fflush(StrmPtr);
  773.             strcpy(LastFileNm, TempFN);
  774.             Mtch1st = 0;
  775.          }
  776.       }
  777.    }
  778. }
  779.  
  780. /* This procedure initializes the "beginning" and "end arg" numbers for the  */
  781. /* NextFile function. Some command line interpreters                         */
  782. /* automatically expand wild cards which makes it hard to know which         */
  783. /* absolute argument ends the list of file names. This function terminates   */
  784. /* the list with the 1st "-" or when a certain # of arguments are left.      */
  785. /* Input parameters NumBefore and NumAfter are constants used to make this   */
  786. /* routine generic for different CLI command formats.                        */
  787.  
  788. int InitNextFile(argv, argc, NumBefore, NumAfter)
  789.    int argc; char *argv[];
  790.    int NumBefore; /* Number of arguments before filenames start but not      */
  791.                   /* including the cmd itself or any "-" arguments.          */
  792.                   /* This is provided to support generic reusability.        */
  793.    int NumAfter;  /* Number of arguments after filenames end. No "-" args    */
  794. {
  795.    extern int CmdLnArgIdx, LstCmdLnArgIdx, RecursFlg;
  796.    int ArgCSav; char **ArgVSav;
  797.    int NumB, NumA;
  798.    char *CmdPtr;
  799.  
  800.    CmdLnArgIdx = 0;
  801.    NumB = NumBefore;
  802.    ArgVSav = argv;
  803.    ArgCSav = argc;
  804. /* Assign CmdLnArgIdx the index of the first filename on the command line    */
  805.    while (( NumB >= 0) && (CmdLnArgIdx < ArgCSav)) {
  806.       CmdPtr = *(++ArgVSav);
  807.       CmdLnArgIdx++;
  808.       if (*CmdPtr != '-') NumB--;
  809.    }
  810.    if (CmdLnArgIdx == ArgCSav) { ErrP("InitNextFile: # before too large\n"); }
  811.    NumA = NumAfter;
  812.    ArgVSav = &argv[argc];
  813. /* Assign LstCmdLnArgIdx the index of the last filename on the command line */
  814.    LstCmdLnArgIdx = argc;
  815.    while (( NumA >= 0) && (LstCmdLnArgIdx > 0)) {
  816.       CmdPtr = *(--ArgVSav);
  817.       LstCmdLnArgIdx--;
  818.       if (*CmdPtr != '-') NumA--;
  819.       else { NumA--; }
  820.    }
  821.    if (LstCmdLnArgIdx == 0) { ErrP("InitNextFile: # args after too large\n"); }
  822. }
  823.  
  824. /* This function is used to parse the command line for filenames. The        */
  825. /* InitNextFile procedure does the initial work to find absolute beginning   */
  826. /* and ending argument numbers and this function uses those numbers to       */
  827. /* retrieves a directory and wildcard pattern from the command line and      */
  828. /* search for any files matching the pattern. Each time it is called, it     */
  829. /* returns a pointer to another full pathname until no more match. Then it   */
  830. /* does the same thing with the next command line argument until all command */
  831. /* line args are tried. A NULL pointer returned means no more matches exist. */
  832.  
  833. char *NextFile(ArgVSav)
  834.    char *ArgVSav[];
  835. {
  836.    extern int CmdLnArgIdx, LstCmdLnArgIdx, RecursFlg;
  837.    static FnshdRecurs = 1;
  838.    static LLines LstDirNm = "\0"; /* Init to empty string */
  839.    static LLines FullPathNm;
  840.    DIB *TmpPtr;
  841.    static int StopOnMatch;
  842.    DIB *NewPtr;
  843.    FIB *TmpFIBPtr;
  844.    BPTR CLock, NewLock, TLock;
  845.    char *PathNmPtr1;
  846.    char *PathNmPtr2;
  847.    char *EndOfDir;
  848.    static char *CurFileNm;
  849.    static char *ScanAll = "*";
  850.    static LLines CurDirName;
  851.    static LLines SavDirName;
  852.    char *StrtOfPathNm;
  853.    int FileNtFnd = 1;
  854.    int Len;
  855.    int ii;
  856.    char *Sidx;
  857.    char *Sidx2;
  858.    char *FName;
  859.  
  860.    do {
  861.       if( CmdLnArgIdx > LstCmdLnArgIdx ) {
  862.          if( LstDirNm[0] != '\0') {
  863.             UnLock( CurDirPtr->CurLock );
  864.             TLock = CurrentDir( CurDirPtr->OldLock );
  865.             FreeMem( CurDirPtr, ( long ) sizeof ( struct DirInfoBlock ) );
  866.             CurDirPtr = NULL;
  867.          }
  868.          return(NULL);
  869.       }
  870.       if (FnshdRecurs) { /* get and decode next cmd line argument */
  871.          StrtOfPathNm = ArgVSav[ CmdLnArgIdx ];
  872.          if( *StrtOfPathNm == '-' ) {
  873.             CmdLnArgIdx++;
  874.             continue;
  875.          }
  876.          FnshdRecurs = 0;
  877.          if( strpbrk( StrtOfPathNm, ":/") != NULL) { /* has dir info */
  878.             /* get directory pathname from command line */
  879.             if( (unsigned long)(PathNmPtr1 = strrchr( StrtOfPathNm, ':')) >
  880.                 (unsigned long)(PathNmPtr2 = strrchr( StrtOfPathNm, '/')) ) {
  881.                EndOfDir = PathNmPtr1 + 1;
  882.             }
  883.             else {
  884.                EndOfDir = PathNmPtr2 + 1;
  885.             }
  886.             if( (EndOfDir - StrtOfPathNm + 1) > LONGWIDTH )
  887.                ErrP("File pathname too long. Aborting...\n");
  888.             mystrncpy( CurDirName, StrtOfPathNm, EndOfDir - StrtOfPathNm + 1);
  889.             /* get pointer to start of filename in pathname */
  890.             CurFileNm = EndOfDir;
  891.          }
  892.          else { /* cmd ln arg only has file info */
  893.             /* get pointer to start of filename in pathname */
  894.             CurFileNm = StrtOfPathNm;
  895.             CurDirName[0] = ' '; /* flag as default directory */
  896.             CurDirName[1] = '\0';
  897.          }
  898.          /* ifonly given dir name, fill in filename to match any file in dir */
  899.          if( CurFileNm[0] == '\0' ) {
  900.             CurFileNm = ScanAll;
  901.          }
  902.          if( strpbrk( CurFileNm, "*?.") == NULL ) {
  903.             if( CurDirName[0] == ' ' ) { strcpy( CurDirName, CurFileNm); }
  904.             else {
  905.                if( strlen(CurDirName) + strlen(CurFileNm) >= LONGWIDTH )
  906.                   ErrP("Total file pathname too long. Aborting...\n");
  907.                strcat( CurDirName, CurFileNm);
  908.             }
  909.             strcat( CurDirName, "/" );
  910.             CurFileNm[0] = '*';
  911.             CurFileNm[1] = '\0';
  912.          }
  913.          StopOnMatch = 1;
  914.          if( (strpbrk( CurFileNm, "*?") != NULL) || RecursFlg) {
  915.             StopOnMatch = 0; /* has wildcard or is recursive */
  916.          }
  917.          if(strcmp(LstDirNm,CurDirName)){/*lstdir!sameas cur */
  918.             /* if last dir was locked, then free it */
  919.             if( LstDirNm[0] != '\0') {
  920.                UnLock( CurDirPtr->CurLock );
  921.                TLock = CurrentDir( CurDirPtr->OldLock );
  922.                FreeMem( CurDirPtr, ( long ) sizeof ( struct DirInfoBlock ) );
  923.                CurDirPtr = NULL;
  924.             }
  925.             strcpy(LstDirNm, CurDirName);
  926.             /* The FileInfoBlock structure has to be long-word alligned, so */
  927.             /* we should use AllocMem to insure this condition is met. */
  928.             CurDirPtr = AllocMem((long)sizeof(struct DirInfoBlock),
  929.                MEMF_PUBLIC | MEMF_CLEAR);
  930.             CurDirPtr->BackLink = NULL; /* anchor */
  931.             /* Get a lock on the upper level Directory */
  932.             if((strpbrk( CurDirName, ":") == NULL)) {
  933.                /* lock the current default directory */
  934.                if(!strcmp(CurDirName, " ")) CurDirName[0] = '\0';
  935.                CurDirPtr->CurLock = Lock( (UBYTE *)CurDirName, ACCESS_READ );
  936.                if (!CurDirPtr->CurLock) {
  937.                   fprintf(stderr,"Err with dir-> %s\n",CurDirName);
  938.                   ErrP("Could not get lock on upper directory\n");
  939.                }
  940.                CurDirPtr->OldLock = CurrentDir(CurDirPtr->CurLock);
  941.                TmpFIBPtr = (FIB *)AllocMem((long)sizeof(FIB),
  942.                   MEMF_PUBLIC | MEMF_CLEAR);
  943.                CLock = CurDirPtr->CurLock;
  944.                ii = LONGWIDTH - 1;
  945.                /* build full pathname of current default directory */
  946.                while (CLock) {
  947.                   NewLock = ParentDir(CLock);
  948.                   Examine(CLock, TmpFIBPtr);
  949.                   FName = TmpFIBPtr->fib_FileName;
  950.                   if (*FName == '\0')
  951.                      FName = "ram";
  952.                   Len = strlen(FName);
  953.                   if (NewLock) {
  954.                      ii -= Len + 1;
  955.                      if( ii < 0 )
  956.                         ErrP("Full pathname too long. Aborting...\n");
  957.                      memcpy(CurDirName + ii, FName, Len);
  958.                      CurDirName[ii+Len] = '/';
  959.                   }
  960.                   else {
  961.                      ii -= Len + 1;
  962.                      if( ii < 0 )
  963.                         ErrP("Full pathname too long. Aborting...\n");
  964.                      memcpy(CurDirName + ii, FName, Len);
  965.                      CurDirName[ii+Len] = ':';
  966.                   }
  967.                   if(CLock != CurDirPtr->CurLock) { UnLock(CLock); }
  968.                   CLock = NewLock;
  969.                }
  970.                FreeMem(TmpFIBPtr, (long)sizeof(FIB));
  971.                memmove(CurDirName, CurDirName + ii, LONGWIDTH - ii);
  972.                CurDirName[LONGWIDTH - ii - 1] = '\0';
  973.                strcpy(SavDirName, CurDirName);
  974.                TLock = CurrentDir(CurDirPtr->OldLock);
  975.             }
  976.             else {
  977.                strcpy(SavDirName, CurDirName);
  978.                CurDirPtr->CurLock = Lock((UBYTE *)CurDirName, ACCESS_READ );
  979.                if (!CurDirPtr->CurLock) {
  980.                   fprintf(stderr,"Error with dir-> %s\n",CurDirName);
  981.                   ErrP("Could not get lock on upper directory\n");
  982.                }
  983.                CurDirPtr->OldLock = CurrentDir(CurDirPtr->CurLock);
  984.                if( CurDirPtr->OldLock == 0) {
  985.                   fprintf(stderr,"Error with dir-> %s\n",CurDirName);
  986.                   ErrP("Could not set current directory\n");
  987.                }
  988.             }
  989.          }
  990.          else { /* last directory name is same as current so copy it */
  991.             strcpy(CurDirName, SavDirName);
  992.          }
  993.          if ( !Examine( CurDirPtr->CurLock, (FIB *)CurDirPtr )) {
  994.             /* upper directory is empty so terminate this tree */
  995.             FnshdRecurs = 1;
  996.          }
  997.          if( ((FIB *)CurDirPtr)->fib_DirEntryType <= 0) {
  998.             /* Program normally assumes last part of a pathname is a         */
  999.             /* directory unless there is a "*", "?", or "." in it. It comes  */
  1000.             /* here if it thought it is a directory when it's really a file. */
  1001.             FnshdRecurs = 0;
  1002.             UnLock( CurDirPtr->CurLock );
  1003.             CurDirName[strlen(CurDirName)-1] = '\0';
  1004.             /* Get position of last "/" or ":" in current dir name,  */
  1005.             /* whichever is greater                                  */
  1006.             Sidx = strchr(CurDirName,':');
  1007.             if( (Sidx2=strrchr(CurDirName,'/')) != NULL ) Sidx = Sidx2;
  1008.             /* Copy stuff after last "/" or ":" to filename string   */
  1009.             strcpy( CurFileNm, Sidx+1 );
  1010.             /* Delete it from current directory name                 */
  1011.             *(Sidx+1) = '\0';
  1012.             CurDirPtr->CurLock = Lock( (UBYTE *)CurDirName, ACCESS_READ );
  1013.             if (!CurDirPtr->CurLock) {
  1014.                fprintf(stderr,"Err with dir-> %s\n",CurDirName);
  1015.                ErrP("Could not get lock on upper directory\n");
  1016.             }
  1017.             if ( !Examine( CurDirPtr->CurLock, (FIB *)CurDirPtr )) {
  1018.                /* upper directory is empty so terminate this tree */
  1019.                FnshdRecurs = 1;
  1020.             }
  1021.          }
  1022.       }
  1023.       while ( !ExNext( CurDirPtr->CurLock, (FIB *)CurDirPtr)) {
  1024.          if (CurDirPtr->BackLink != NULL) {
  1025.             /* pop directory */
  1026.             UnLock( CurDirPtr->CurLock );
  1027.             TLock = CurrentDir( CurDirPtr->OldLock );
  1028.             TmpPtr = CurDirPtr->BackLink;
  1029.             FreeMem( CurDirPtr, ( long ) sizeof ( struct DirInfoBlock ) );
  1030.             CurDirPtr = TmpPtr;
  1031.          }
  1032.          else {
  1033.             /* Dont pop from upper most dir since we may need it later */
  1034.             FnshdRecurs = 1;
  1035.             break;
  1036.          }
  1037.       }
  1038.       while (!FnshdRecurs && (((FIB *)CurDirPtr)->fib_DirEntryType > 0)) {
  1039.          if (RecursFlg) {
  1040.             TmpPtr = CurDirPtr;
  1041.             CurDirPtr = AllocMem((long)sizeof(struct DirInfoBlock),
  1042.                MEMF_PUBLIC | MEMF_CLEAR);
  1043.             CurDirPtr->BackLink = TmpPtr;
  1044.             /* Get a lock on the Current Directory */
  1045.             CurDirPtr->CurLock =
  1046.                     Lock((UBYTE *)(((FIB *)TmpPtr)->fib_FileName),ACCESS_READ);
  1047.             if (CurDirPtr->CurLock == 0) {
  1048.                fprintf(stderr,"Could not get lock on intermediate dir\n");
  1049.                TmpPtr = CurDirPtr->BackLink;
  1050.                FreeMem( CurDirPtr, ( long )sizeof( struct DirInfoBlock ));
  1051.                CurDirPtr = TmpPtr;
  1052.             }
  1053.             else {
  1054.                CurDirPtr->OldLock = CurrentDir(CurDirPtr->CurLock);
  1055.                if ( !Examine( CurDirPtr->CurLock, (FIB *)CurDirPtr )) {
  1056.                   if (CurDirPtr->BackLink != NULL) {
  1057.                      /* pop dir */
  1058.                      UnLock( CurDirPtr->CurLock );
  1059.                      TLock = CurrentDir( CurDirPtr->OldLock );
  1060.                      TmpPtr = CurDirPtr->BackLink;
  1061.                      FreeMem( CurDirPtr, ( long )sizeof( struct DirInfoBlock ));
  1062.                      CurDirPtr = TmpPtr;
  1063.                   }
  1064.                   else {
  1065.                      /* Dont pop from upper most dir since we may need it later */
  1066.                      FnshdRecurs = 1;
  1067.                      break;
  1068.                   }
  1069.                }
  1070.             }
  1071.          }
  1072.          while ( !ExNext( CurDirPtr->CurLock, (FIB *)CurDirPtr)) { /* pop dir */
  1073.             if (CurDirPtr->BackLink != NULL) {
  1074.                UnLock( CurDirPtr->CurLock );
  1075.                TLock = CurrentDir( CurDirPtr->OldLock );
  1076.                TmpPtr = CurDirPtr->BackLink;
  1077.                FreeMem( CurDirPtr, ( long ) sizeof ( struct DirInfoBlock ) );
  1078.                CurDirPtr = TmpPtr;
  1079.             }
  1080.             else {
  1081.                /* Dont pop from upper most dir since we may need it later */
  1082.                FnshdRecurs = 1;
  1083.                break;
  1084.             }
  1085.          }
  1086.       }
  1087.       if( FnshdRecurs ) { CmdLnArgIdx++; }
  1088.       else {
  1089.          /* test if file matches pattern */
  1090. /*            printf("%s\n", (((FIB *)CurDirPtr)->fib_FileName) );       */
  1091.          if( newwildcmp( CurFileNm, ((FIB *)CurDirPtr)->fib_FileName)) {
  1092.             FileNtFnd = 0;
  1093.          }
  1094.       }
  1095.    }
  1096.    while( FileNtFnd );
  1097.    ii = LONGWIDTH - 1;
  1098.    NewPtr = CurDirPtr;
  1099.    do {
  1100.       TmpPtr = NewPtr;
  1101.       FName = ((FIB *)TmpPtr)->fib_FileName;
  1102.       Len = strlen(FName);
  1103.       if (ii == LONGWIDTH - 1) {
  1104.          ii -= Len;
  1105.          if( ii < 0 ) ErrP("Full pathname too long. Aborting...\n");
  1106.          memcpy(FullPathNm + ii, FName, Len);
  1107.       }
  1108.       else {
  1109.          ii -= Len + 1;
  1110.          if( ii < 0 ) ErrP("Full pathname too long. Aborting...\n");
  1111.          memcpy(FullPathNm + ii, FName, Len);
  1112.          FullPathNm[ii+Len] = '/';
  1113.       }
  1114.       NewPtr = TmpPtr->BackLink;
  1115.    }
  1116.    while( TmpPtr->BackLink != NULL );
  1117.    Len = strlen(CurDirName);
  1118.    ii -= Len;
  1119.    if( ii < 0 ) ErrP("Full pathname too long. Aborting...\n");
  1120.    memcpy(FullPathNm + ii, CurDirName, Len);
  1121.    memmove(FullPathNm, FullPathNm + ii, LONGWIDTH - ii);
  1122.    FullPathNm[LONGWIDTH - ii - 1] = '\0';
  1123.    if (StopOnMatch) {
  1124.       FnshdRecurs = 1;
  1125.       while (CurDirPtr->BackLink != NULL) {
  1126.          /* pop directory */
  1127.          UnLock( CurDirPtr->CurLock );
  1128.          TLock = CurrentDir( CurDirPtr->OldLock );
  1129.          TmpPtr = CurDirPtr->BackLink;
  1130.          FreeMem( CurDirPtr, ( long ) sizeof ( struct DirInfoBlock ) );
  1131.          CurDirPtr = TmpPtr;
  1132.       }
  1133.       CmdLnArgIdx++;
  1134.       StopOnMatch = 0;
  1135.    }
  1136.    return( FullPathNm );
  1137. }
  1138.  
  1139. long SubPatFreq(SubPat) /* LSB is 0.000001 percent */
  1140. unsigned short SubPat;
  1141. {                     /* Expected frequency of char in hundredth of percents */
  1142.    int Freq[256] = {    10,    10,    10,    10,    10,    10,    10,    10,
  1143.                         10,    10,    10,    10,    10,    10,    10,    10,
  1144.                         10,    10,    10,    10,    10,    10,    10,    10,
  1145.                         10,    10,    10,    10,    10,    10,    10,    10,
  1146. /*                    " "     !      "      #      $      %      &      '    */
  1147.                       1000,    10,   100,    10,   100,    10,    10,    10,
  1148. /*                     (      )      *      +      ,      -      .      /    */
  1149.                        100,   100,   100,    10,   100,    10,   100,   100,
  1150. /*                     0      1      2      3      4      5      6      7    */
  1151.                        500,   500,   500,   500,   500,   500,   500,   500,
  1152. /*                     8      9      :      ;      <      =      >      ?    */
  1153.                        500,   500,   100,    50,   100,   100,   100,   100,
  1154. /*                     @      A      B      C      D      E      F      G    */
  1155.                        100,   810,   140,   270,   380,  1300,   290,   200,
  1156. /*                     H      I      J      K      L      M      N      O    */
  1157.                        520,   630,    13,    40,   340,   250,   710,   790,
  1158. /*                     P      Q      R      S      T      U      V      W    */
  1159.                        190,    11,   680,   610,  1050,   240,    90,   150,
  1160. /*                     X      Y      Z      [      \      ]      ^      _    */
  1161.                        150,   190,    07,   100,   100,   100,    10,    10,
  1162. /*                    " "     a      b      c      d      e      f      g    */
  1163.                        100,   810,   140,   270,   380,  1300,   290,   200,
  1164. /*                     h      i      j      k      l      m      n      o    */
  1165.                        520,   630,    13,    40,   340,   250,   710,   790,
  1166. /*                     p      q      r      s      t      u      v      w    */
  1167.                        190,    11,   680,   610,  1050,   240,    90,   150,
  1168. /*                     x      y      z      {      |_     }                  */
  1169.                        150,   190,     7,   100,   100,   100,   100,  1000,
  1170.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1171.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1172.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1173.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1174.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1175.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1176.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1177.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1178.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1179.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1180.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1181.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1182.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1183.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1184.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000,
  1185.                       1000,  1000,  1000,  1000,  1000,  1000,  1000,  1000  };
  1186.  
  1187.    return( Freq[ (SubPat >> 8) & 255 ] * Freq[ SubPat & 255 ]);
  1188. }
  1189.  
  1190. PrntHlp()
  1191. {
  1192.    fprintf(stderr,"scan's pattern matching algorithm:\n"
  1193.    "  ?          Matches any single character except newline\n"
  1194.    "  [chars]    Match any characters within braces\n"
  1195.    "  [c1-c2]    Match any characters from c1 to c2\n"
  1196.    "  [^chars]   Match any characters not within braces\n"
  1197.    "  \\xYY       Matches hex number YY as a character\n"
  1198.    "  \\Y         Matches the standard C escape sequence Y\n"
  1199.    "  \\YYY       Matches the decimal number YYY as a character\n"
  1200.    "  |          Either pattern on left or right must match\n"
  1201.    "  +          Same as | \n"
  1202.    "  *          Pattern on left and right must both match and be in same\n"
  1203.    "             word. Match on left must come before match on right.\n"
  1204.    "  #?         Same as *.\n"
  1205.    "  &          Pattern on left and right must both match and be in same\n"
  1206.    "             sentence. Match on left must come before match on right.\n"
  1207.    "  ..         Pattern on left and right must both match and be in same\n"
  1208.    "             article. Order of left and right matches is not important.\n"
  1209.    "             This is alot faster than &. This is only useful during\n"
  1210.    "             article scans.\n"
  1211.    "scan's config file format(there is an implicit | after each pattern):\n"
  1212.    "  article separator\n"
  1213.    "  column article separator must be in. 0 -> ignore\n"
  1214.    "  invert match flag. 1 -> invert match. 0 -> normal\n"
  1215.    "  window size in bytes\n"
  1216.    "  search pattern1\n"
  1217.    "          .\n"
  1218.    "  search patternN\n"
  1219.    );
  1220. }
  1221.  
  1222. main(argc, argv)
  1223. int argc; char *argv[];
  1224. {
  1225.    int ArgCSav; char **ArgVSav;
  1226.    /* StrtTime = clock(); */
  1227. // printf("%ld %s %s %s %s %s\n",argc,argv[1],argv[2],argv[3],argv[4],argv[5]);
  1228.  
  1229. /* Scan the command line and initialize based on different options */
  1230.    ArgVSav = argv; ArgCSav = argc;
  1231.    HasCnfgF = 0;
  1232.    NumAfter = 1;
  1233.    LineScan = 1;
  1234.    for (++argv; --argc; ++argv) {
  1235.       PndQues2Ast( *argv );
  1236.       InName = *argv;
  1237.       if (*InName++ == '-') {
  1238.          TermLp = 0;
  1239.          while((*InName != 0) && !TermLp) {
  1240.             switch(*InName++) {
  1241.                case('a'): LineScan = 0; break;
  1242.                case('c'): if (sscanf(InName,"%d",&ColReq)) {
  1243.                              while( isdigit( (int)(*InName))) InName++;
  1244.                              break;
  1245.                           }
  1246.                           else { ErrP("Bad column for article separator\n"); }
  1247.                case('f'): HasCnfgF = 1; NumAfter = 0;
  1248.                           if ((ConfigF = fopen(InName,"r")) == NULL) {
  1249.                              if(*InName != 0) ErrP("Bad config file name\n");
  1250.                              if((ConfigF = fopen("s:scan.config","r")) == NULL)
  1251.                                 ErrP("Could not open s:scan.config\n");
  1252.                           }
  1253.                           /* Handle initialization of article separator,     */
  1254.                           /* article column, window size, common words, and  */
  1255.                           /* inverse pattern from configuration file.        */
  1256.                           if (fscanf(ConfigF,"%s\n",ArtBuf) != 1) ErrP("Could"
  1257.                              " not read article separator from config file\n");
  1258.                           ArtSep = EOASep = ArtBuf;
  1259.                           while (*EOASep != '\0') EOASep++;
  1260.                           --EOASep;
  1261.                           if (fscanf(ConfigF,"%d\n",&ColReq) != 1)
  1262.                              ErrP("Bad column for article separator\n");
  1263.                           if (fscanf(ConfigF,"%d\n",&InvertMatch) != 1)
  1264.                              ErrP("Err reading match inversion flag\n");
  1265.                           if (fscanf(ConfigF,"%ld\n",&WinSiz) != 1) ErrP(
  1266.                              "Could not read window size from config file\n");
  1267.                           /* Initialize Min Term Array with pattern to       */
  1268.                           /* search for from config file                     */
  1269.                           EndMin = &MinArray[0] + sizeof(MinArray);
  1270.                           while ((fgets(Stf1, LWIDTH-1, ConfigF) > 0) &&
  1271.                              (MinTerm != EndMin)) if(*Stf1!='\n')
  1272.                              strcpy((char *)MinTerm++, strtok(Stf1,";\n\0"));
  1273.                           if( MinTerm == EndMin) ErrP(
  1274.                              "Too many patterns to search for. Aborting...\n");
  1275.                           if (ferror(ConfigF)) ErrP("Error reading"
  1276.                              " config file search pattern. Aborting...\n");
  1277.                           fclose(ConfigF);
  1278.                           ConfigF = 0;
  1279.                           LineScan = 0;
  1280.                           TermLp = 1;
  1281.                           break;
  1282.                case('h'): if( isdigit( (int)(*InName))) {
  1283.                              HighLightColor[2] = *InName++;
  1284.                              if( isdigit( (int)(*InName))) {
  1285.                                 PathNmColor[2] = *InName++;
  1286.                              }
  1287.                           }
  1288.                           break;
  1289.                case('i'): InvertMatch = 1; break;
  1290. /* Do a line search instead of an article search. Print out xx lines around  */
  1291. /* match, where xx is a number following the -l.                             */
  1292.                case('l'): LineScan = 1; PrntWidth = atoi(InName);
  1293.                           while( isdigit( (int)(*InName))) InName++;
  1294.                           break;
  1295.                case('n'): LineNum = 1; break;
  1296. /* Without -o option, strmptr defaults to stdout */
  1297.                case('o'): if ((OutFile = fopen(InName,"w")) == NULL)
  1298.                              ErrP("Could not open output file\n");
  1299.                           RealFile = 1; StrmPtr = OutFile;
  1300.                           TermLp = 1; break;
  1301.                case('p'): AlwaysPrint = 1; break;
  1302.                case('r'): RecursFlg = 1; break;
  1303. /* Without -s option, the article separator defaults to "Article" */
  1304.                case('s'): ArtSep = InName;
  1305.                           while(*InName != 0) { InName++; }
  1306.                           EOASep = --InName; TermLp = 1; break;
  1307.                case('t'): Trunc = 1; break;
  1308.                case('v'): fprintf(stderr,"Scan version 1.0 by Walter Rothe, "
  1309.                           "Copyright © 1991,1992.\n");
  1310.                           CleanIt();
  1311.                           exit(1);
  1312. /* Without -w option, window size defaults to 16kb */
  1313.                case('w'): if(sscanf(InName,"%ld",&WinSiz)) {
  1314.                              while( isdigit( (int)(*InName))) InName++;
  1315.                              break;
  1316.                           }
  1317.                           else { ErrP("Bad window size\n"); }
  1318.                case('x'): PrntHlp(); CleanIt(); exit(1);
  1319.                case('z'): if( *InName ) WildLZH = InName;
  1320.                           EnableLZHDecomp = 1;
  1321.                           TermLp = 1; break;
  1322.             }
  1323.          }
  1324.       }
  1325.       else { LastArg = --InName; } /* save last non "-" arg on cmd line */
  1326.    }
  1327.  
  1328.    if (ArgCSav < 3) {
  1329.       fprintf(stderr,
  1330.       " Copyright © 1991,1992 by Walter Rothe.\n"
  1331.       " + Scan SrchFile(s) Pattern -[hlnoprtwz]       OR\n"
  1332.       " - Scan SrchFile(s) -f[CnfgFile] -[orz]        OR\n"
  1333.       " @ Scan SrchFile(s) Pattern -a[cioprswz]       OR\n"
  1334.       " # Scan -[vx]\n"
  1335.       "   SrchFile  :+-@ Pathname of file(s) to be searched\n"
  1336.       "   Pattern   :+@  What to srch for; Ex. sale..d*paint[3i]+paint&prog\n"
  1337.       "   -a        :@   Article scan. Prints out all articles with matches.\n"
  1338.       "   -cColumn  :@   Column article separtor must be in(1..?)\n"
  1339.       "   -fCnfgFile:@   Get parms from config file\n"
  1340.       "   -f        :@   Get parms from s:scan.config\n"
  1341.       "   -hxy      :+   Highlight match with x color and pathname, y color.\n"
  1342.       "   -i        :@   Invert matching so nonmatching articles are printed\n"
  1343.       "   -lxx      :+   Line search with xx lines around target printed\n"
  1344.       "   -n        :+   Print line numbers with matched text(slower)\n"
  1345.       "   -oOutFile :+-@ Send output to file\n"
  1346.       "   -p        :+-@ Always print file pathnames scanned\n"
  1347.       "   -r        :+-@ Recursively scan down directories\n"
  1348.       "   -sArtSep  :@   Article separator(def Article)\n"
  1349.       "   -t        :+   Truncate output to window width. Only works with -n\n"
  1350.       "   -v        :#   Print version number. Other options nulled.\n"
  1351.       "   -wWinSize :+@  Window size(def 16384 bytes). Mod(size,4) must be 0\n"
  1352.       "   -x        :#   Print out more help info. Nulls other options\n"
  1353.       "   -zWildPat :+-@ Decompres .lzh/.lha with int files matching WildPat\n"
  1354.       "   -z        :+-@ Decompress all .lzh and .lha files before scanning.\n"
  1355.       );
  1356.       CleanIt();
  1357.       exit(1);
  1358.    }
  1359.  
  1360. /* If doing a line search, turn off inverted pattern matching. and set      */
  1361. /* article separator to a pattern that should never occur.                  */
  1362.    if (LineScan) {
  1363.       InvertMatch = 0;
  1364.       ArtSep = EOASep = LineSrchDelim;
  1365.       while (*EOASep != '\0') {
  1366.          EOASep++;
  1367.       }
  1368.       --EOASep;
  1369.    }
  1370.    else {
  1371.       if( (ColReq > LWIDTH) || (ColReq < 0) ) {
  1372.          ErrP("Column # for article sep too large or neg. Aborting...\n");
  1373.       }
  1374.    }
  1375.  
  1376. /* For LH5 decompression, window size must be at least 8192.
  1377.    if( EnableLZHDecomp ) WinSiz = 16384;
  1378.  
  1379. /* Init pointers and data so NextFile function can be called sequentially   */
  1380.    InitNextFile(ArgVSav, ArgCSav, NumBefore, NumAfter);
  1381.  
  1382. /* If inverted matching, set to not print out when 1st article header found */
  1383.    if (InvertMatch) { OutArt = 1; }
  1384.  
  1385. /* Find 1st filename to scan and open it and read in 1st buffer and start */
  1386. /* an asyncronous read to fill the 2nd buffer.                            */
  1387.  
  1388.    if ((FName = NextFile(ArgVSav)) != NULL) {
  1389.       if ((FHandle = xfropen(FName,&ReadNum)) == NULL) {
  1390.          ErrP("Problems opening 1st file to scan\n");
  1391.       }
  1392.       if (ReadNum < 0) {
  1393.          ErrP("Could not read any data from 1st file\n");
  1394.       }
  1395.    }
  1396.    else {
  1397.       ErrP("No files found to scan\n");
  1398.    }
  1399.  
  1400. /* Get text width for later */
  1401.    if( !RealFile ) {
  1402.       TextWidth = WindowSize();
  1403.    }
  1404.  
  1405.    PathPrint(MatchNotFnd);
  1406.  
  1407.    LstOut = SOCB;
  1408.  
  1409. /* parse out the min terms from command line argument */
  1410.    if (!HasCnfgF) {
  1411.       TmpTrm = strtok(LastArg++,"+|");
  1412.       if( strlen(TmpTrm) >= LWIDTH) {
  1413.          ErrP("A minterm in the pattern is too long. Aborting...\n");
  1414.       }
  1415.       while (TmpTrm != 0) {
  1416.          strcpy((char *)(MinTerm++), TmpTrm );
  1417.          TmpTrm = strtok(NULL,"+|");
  1418.       }
  1419.    }
  1420.  
  1421. /* Convert any backslashes in minterm array to their equivalent char     */
  1422.    MinPtr = &MinArray[0];
  1423.    while ( MinPtr != MinTerm ) {
  1424.       BackSlash(MinPtr);
  1425.       PndQues2Ast(MinPtr++);
  1426.    }
  1427.  
  1428. /* Convert any backslashes in article separator to their equivalent char */
  1429.    BackSlash(ArtSep);
  1430.    EOASep = ArtSep;
  1431.    while (*EOASep != '\0') { EOASep++; } /* get pntr to end of art sep   */
  1432.    --EOASep;
  1433.    if( (EOASep - ArtSep + 1 >= LWIDTH) || (EOASep - ArtSep + 1 >= MAXKWSZ))
  1434.       ErrP("Article separator too long. Aborting...\n");
  1435.  
  1436. /* printout list of min terms, art sep, win size */
  1437.  
  1438. #ifdef DEBUG
  1439.    printf("Window size is %ld \n", WinSiz);
  1440.    printf("Article separator is %s \n", ArtSep);
  1441.    MinPtr = &MinArray[0];
  1442.    while ( MinPtr != MinTerm ) {
  1443.       printf("%s \n",MinPtr++);
  1444.    }
  1445. #endif
  1446.  
  1447. /* Generate list of major terms from list of minterms. Note that 1 is   */
  1448. /* reserved for the article separator and 2 for the end of buffer key.  */
  1449. /* 0 is not used. If there are more than 127, there will be a slowdown  */
  1450. /* since the duplicate keyword algorithm must be used.                  */
  1451.  
  1452. /* Create a table, indexed by major term number of what it's minterm    */
  1453. /* number is. It is called MajTrm2MinTrm.                               */
  1454.  
  1455. /* Create a table, indexed by major term number, mapping it to a bit    */
  1456. /* number in the MinSatTbl. This is a number from 0 to 31 and is        */
  1457. /* assigned according to its order; the 1st major term encountered      */
  1458. /* for a new minterm in the pattern is assigned 0, and the next 1, etc. */
  1459. /* This table is called MajTrm2BitNum.                                  */
  1460.  
  1461. /* Create a table, indexed by major term number, indicating if the      */
  1462. /* associated minterm is satisfied by this major term only, or not.     */
  1463. /* This table is called MinSatByMTOnly and contains 0 or 1.             */
  1464.  
  1465. /* Create a table, indexed by minterm number, containing a bit field,   */
  1466. /* and mask for the bit field. Every time a major term is found, a bit  */
  1467. /* is set in the appropriate bit field and the mask applied. If the     */
  1468. /* result is -1, then the minterm is satisfied. This table is called    */
  1469. /* MinSatTbl.                                                           */
  1470.  
  1471.    MinPtr = &MTArray[0];
  1472.    strcpy((char *)(MinPtr++), ArtSep);
  1473.    strcpy((char *)(MinPtr), EOBK);
  1474.  
  1475.    if ((LstMajTrm = GetMajTrms()) == NULL) {
  1476.       ErrP("Error building major term table\n");
  1477.    }
  1478.  
  1479.    MinPtr = &MTArray[0];
  1480.  
  1481. #ifdef DEBUG
  1482.    while ( MinPtr != LstMajTrm ) {
  1483.       printf("%s \n",MinPtr++);
  1484.    }
  1485.    printf("number of minterms is %d \n",NumOfMinTrms);
  1486.    printf("number of majterms is %d \n",NumOfMajTrms);
  1487. #endif
  1488.  
  1489. /* Create a table, indexed by major term number, containing daisy       */
  1490. /* chained pointers of major terms found in the article. When the       */
  1491. /* article delimiter is found, this table is traversed to determine     */
  1492. /* which bit fields to reset. This table is initially nulled out so     */
  1493. /* detection of loops is possible. When the article delimiter is found, */
  1494. /* the pointers are set back to null again. If a loop is detected, it's */
  1495. /* pointer is not modified and the variable LastMT is not modified.     */
  1496. /* This table is called LastMTTbl.                                      */
  1497.  
  1498.    for (i=0; i<NumOfMajTrms; i++) { LastMTTbl[i] = 0; }
  1499.    LastMT = 0;
  1500.  
  1501. /* Clear SubPat table                                                   */
  1502.    ClrSubPat();
  1503.  
  1504. /* If we find a two char article separator, increase its length to 3 so */
  1505. /* it will be handled properly. Add a 0x20 char to the end. Later on we */
  1506. /* will copy the subpat value from the 0x20 index to all other possible */
  1507. /* indeces and shorten EOASep back to 2 char from the start.            */
  1508.    if (strlen(ArtSep) < 3) { /* handle two char article separators      */
  1509.       TwoCharArtSep = 1;
  1510.       *((char *)&MTArray[0] + 2) = 0x20;
  1511.       *((char *)&MTArray[0] + 3) = 0x00;
  1512.       *(ArtSep + 2) = 0x20;
  1513.       *(ArtSep + 3) = 0x00;
  1514.       EOASep++;
  1515.    }
  1516.  
  1517. /* Initialize mixed case to lower case conversion table                 */
  1518.  
  1519.    for (i=0; i<256; i++) { LowrCs[i] = tolower(i); }
  1520.  
  1521. /* Create table matching major term # to the length of the MT's longest   */
  1522. /* keyword containing none of the following characters: ?, &, *, and      */
  1523. /* not within brackets. Table is called MajTrm2MaxKeyLen.                 */
  1524. /* Ignore 1st 3 major terms which are 0(reserved), 1(Article separator),  */
  1525. /* and 2(End of buffer). Note that in MTArray, article separator is       */
  1526. /* element 0 and EOB is element 1. Also note difference between MT number */
  1527. /* and MT index. MT index of 2 or 3 matches MT number 1 and 4 or 5        */
  1528. /* matches MT number 2. The 1st MT index is double the MT number. This is */
  1529. /* because there is an odd and even keyword associated with each MT.      */
  1530.  
  1531.    BrakIdx = AllocMem( (long)(MAXMTS*sizeof(BrakTyp1)), 0);
  1532.    BrakPtr = AllocMem( (long)(MAXMTS*sizeof(BrakTyp2)), 0);
  1533.  
  1534.    for (i=1; i<=NumOfMajTrms; i++) {
  1535.       MajTrm2MaxKeyLen[i] = 0;
  1536.       strcpy(Stf1, (char *)&MTArray[i-1]);
  1537.       strcpy(Stf3, (char *)&MTArray[i-1]);
  1538.       j = 0; k = 0; FndBrak = 0; ll = 0;
  1539.       while (Stf1[j]) {                             /* Remove stuff between */
  1540.          if (FndBrak) {                             /* brackets from major  */
  1541.             if (Stf1[j] == ']') {                   /* term and put in Stf1 */
  1542.                FndBrak = 0;
  1543.                BrakIdx[i][k-1] = (unsigned char)ll; /* Limit size of mem rq */
  1544.                BrakPtr[i][ll] = AllocMem((long)256,MEMF_CLEAR);
  1545.                FreeItList[FrI++] = (char *)(BrakPtr[i][ll]);
  1546.                /* load a 1 into characters that will cause a match and 0    */
  1547.                /* into those that wont.                                     */
  1548.                Inv = 0;
  1549.                if(Stf3[StrtBrk+1] == '^') { Inv = 1; StrtBrk++; }
  1550.                for (ci=StrtBrk+1; ci<j; ci++) {
  1551.                   if (Stf3[ci] == '-') {
  1552.                      for (t1 = Stf3[ci-1]; t1 != Stf3[ci+1]; t1++) {
  1553.                         BrakPtr[i][ll][t1] = 1;
  1554.                         BrakPtr[i][ll][toupper(t1)] = 1;
  1555.                      }
  1556.                   }
  1557.                   else {
  1558.                      BrakPtr[i][ll][Stf3[ci]] = 1;
  1559.                      BrakPtr[i][ll][toupper(Stf3[ci])] = 1;
  1560.                   }
  1561.                }
  1562.                if (Inv) for (t1=0; t1<256; t1++) BrakPtr[i][ll][t1] ^= 1;
  1563.                if(++ll >= MAXBRAKS) {
  1564.                   ErrP("Too many bracket wildcards in major term\n");
  1565.                }
  1566.             }
  1567.          }
  1568.          else {
  1569.             if (Stf1[j] == '[') { FndBrak = 1; StrtBrk = j; }
  1570.             if (i < 3) {
  1571.                Stf1[k++] = Stf1[j];                 /* Dont convert art sep */
  1572.             }                                       /* to lower case        */
  1573.             else {
  1574.                Stf1[k++] = LowrCs[Stf1[j]];         /* Keep [ in string for */
  1575.             }                                       /* use as a delimiter   */
  1576.             Stf3[j] = LowrCs[Stf3[j]];
  1577.          }
  1578.          j++;
  1579.       }
  1580.       Stf1[k] = 0;
  1581.       LenSt = strlen(Stf1);
  1582.       NBAryEnd[i] = (char *)&NoBrakAry[i] + LenSt - 1;
  1583.       strcpy( (char *)&NoBrakArray[i], Stf1);       /* Save MT with no      */
  1584.                                                     /* bracket stuff        */
  1585.       strcpy( (char *)&NoBrakAry[i], Stf1);         /* This array will      */
  1586.                                                     /* not be overwritten.  */
  1587.       Tok = strtok( Stf1, "?&*[");                  /* Tokenize Stf1 with   */
  1588.       while (Tok != NULL) {                         /* delimiters of ?&*[.  */
  1589.          if (strlen(Tok) > MajTrm2MaxKeyLen[i]) {   /* Find longest token.  */
  1590.             MajTrm2MaxKeyLen[i] = strlen(Tok);
  1591.          }
  1592.          Tok = strtok( NULL, "?&*[");
  1593.       }
  1594.       if (MajTrm2MaxKeyLen[i] < 2) {
  1595.          fprintf(stderr,"No keyword found in MT longer than 1 char, so\n");
  1596.          fprintf(stderr,"MT>>> %s <<<will be ignored.\n",Stf1);
  1597.       }
  1598.    }
  1599.  
  1600. #ifdef DEBUG
  1601.    for (i=1; i<=NumOfMajTrms; i++) {
  1602.       printf("Maj Trm # %d has a max keyword length of %d\n",i,
  1603.               MajTrm2MaxKeyLen[i]);
  1604.    }
  1605. #endif
  1606.  
  1607. /* Sort all major terms except ArtSep and EOB by the width of their     */
  1608. /* longest keyword containing none of the following                     */
  1609. /* characters: ?, &, *, and not within brackets. Throw out any minterms */
  1610. /* with 1 char keywords. Smallest keyword length 1st.                   */
  1611. /* ArtSep is hard coded to be 1st and EOB 2nd in prioritized list.      */
  1612.  
  1613.    for (i=1; i<=NumOfMajTrms; i++) { MTNumSortedByKeyLen[i] = i; }
  1614.    qsort( &MTNumSortedByKeyLen[3], NumOfMajTrms-2,
  1615.           sizeof(MTNumSortedByKeyLen[3]), MaxVal);
  1616.  
  1617. #ifdef DEBUG
  1618.    printf("Major terms ordered by keyword length follows\n");
  1619.    for (i=3; i<=NumOfMajTrms; i++) {
  1620.       printf("%d\n",MTNumSortedByKeyLen[i]);
  1621.    }
  1622. #endif
  1623.  
  1624. /* Go thru sorted MT list, looking for two two-character sub patterns   */
  1625. /* to indicate the possible presence of the major term in the input     */
  1626. /* buffer. Try to find sub patterns that do not appear often in the     */
  1627. /* buffer. 2 are needed because the search is word(two char) oriented.  */
  1628. /* One for the even byte and one for the odd byte. Note that both       */
  1629. /* have to be in the same keyword although not necessarily overlaping.  */
  1630.  
  1631. /* Starting with the major term with shortest keyword, and proceeding   */
  1632. /* to the MT with the largest, find a two-char subpattern within the MT */
  1633. /* that has the lowest processing time overhead associated with it.     */
  1634. /* Assume the time overhead per 10000 chars, for a single subpat        */
  1635. /* is = SubPatFreq1*t1; where t1 is about 23usec. For a duplicate       */
  1636. /* subpat, the overhead is = SubPatFreq2*(t3+(NumOfDupls+1)*t2);        */
  1637. /* t3 is about 21usec and t2 about 64usec. These times are for a 68K    */
  1638. /* based 7 MHZ system with no wait states. Make sure, if duplicating    */
  1639. /* the subpat, that the base keyword is different. For right now,       */
  1640. /* print out an error and ignore the minterm if you cant find either    */
  1641. /* a nonduplicated subpat or a duplicated one with a different base     */
  1642. /* keyword. Force using dupl subpats when exceeding 128 major terms.    */
  1643.  
  1644. /* Build SubPat table concurrently with assigning two-char subpatterns. */
  1645. /* Use the partially complete SubPat table to find NumOfDupls.          */
  1646.  
  1647.    for (i=1; i<=NumOfMajTrms; i++) {
  1648.       NextMT = MTNumSortedByKeyLen[i];
  1649.       SavTEPat = 0;
  1650.       SavTOPat = 0;
  1651.       TotOH = 2147483647; /* max Overhead(usec) for odd and even sub pattern */
  1652.       Tok = strtok( (char *)&NoBrakArray[NextMT], "?&*["); /* Tokenize with  */
  1653.       while (Tok != NULL) {                          /* delimiters of ?&*[.  */
  1654.          if((TokLen = strlen(Tok)) >= 3) {     /* SubPat must have > 2 chars */
  1655.             CurOddOH = 2147483647;             /* Init to max pos overhead   */
  1656.             CurEvenOH = 2147483647;
  1657.             FndALOGKeyWrd = 0;  /* Found At Least One Good Key Word in token */
  1658.             for (j=0; j<TokLen-1; j=j+2) { /* Go thru token a word at a time */
  1659.                CurPat = (Tok[j] << 8) | Tok[j+1];   /* Construct test subpat */
  1660.                /* If SubPat table does not yet have an entry for CurPat,     */
  1661.                /* and if the limit of 128 Odd and 128 Even SubPats has not   */
  1662.                /* been reached, then compute the overhead for CurPat and if  */
  1663.                /* less than the previous smallest SubPat overhead(for this   */
  1664.                /* token) then save pointers to CurPat.                       */
  1665.                if (((MTNum = SubPat[CurPat]) == 0) && (i < 128)) {
  1666.                   if ((OH = SubPatFreq(CurPat)*T1) < CurEvenOH) {
  1667.                      CurEvenOH = OH;
  1668.                      SavEPat = CurPat;
  1669.                      SavTok = Tok;
  1670.                      SavEIdx = j;
  1671.                      FndALOGKeyWrd = 1;
  1672.                   }
  1673.                }
  1674.                /* If there is currently an element in the SubPat table or if */
  1675.                /* we have exceeded the 128 possible major terms then         */
  1676.                /* determine what the overhead for the subpat would be if it  */
  1677.                /* would be put in the duplicate keyword table. If less than  */
  1678.                /* the previous least overhead subpat, then save it.          */
  1679.                else {
  1680.                   if (MTNum > 5) {    /* Not Article separator or End Of Buf */
  1681.                      if ( DsplTb[MTNum] != 0) { /* One element in SubPat tbl */
  1682.                         /* Overhead must take into account extra overhead 4  */
  1683.                         /* current element and duplicate overhead for new el.*/
  1684.                         /* OH = SubPatFreq*((t3+t2-t1) + (t3+2*t2))          */
  1685.                         MulFct = 2*T3 + 3*T2 - T1;
  1686.                         if ((OH = SubPatFreq(CurPat)*MulFct) < CurEvenOH) {
  1687.                            /* if token is identical to token currently in    */
  1688.                            /* keyword table, bypass this keyword.            */
  1689.                            if (!memcmp(Tok,SvTbl[MTNum],TokLen)){
  1690.                               continue;
  1691.                            }
  1692.                            CurEvenOH = OH;
  1693.                            SavEPat = CurPat;
  1694.                            SavTok = Tok;
  1695.                            SavEIdx = j;
  1696.                            FndALOGKeyWrd = 1;
  1697.                         }
  1698.                      }
  1699.                      else {     /* More than 1 element in table(duplicates). */
  1700.                         NumDup = 1;
  1701.                         TmpPtr = &DKWTbl[MTNum][3];
  1702.                         /* Find number of duplicated subpatterns */
  1703.                         while((TmpPtr=(char **)*(TmpPtr+3)) != NULL){NumDup++;}
  1704.                         /* Overhead is for a duplicated subpattern */
  1705.                         if( (NumDup+1) << ((1<<29)/1000000/T3) ) {
  1706.                            MulFct = T2 + ((NumDup+1)*T3);
  1707.                         }
  1708.                         else {
  1709.                            MulFct = (1<<29)/1000000/T3 + NumDup;
  1710.                         }
  1711.                         /* If overhead is less than previous least overhead  */
  1712.                         /* for other even subpats, then save pntr to CurPat  */
  1713.                         if ((OH = SubPatFreq(CurPat)*MulFct) < CurEvenOH) {
  1714.                            /* if token is identical to token of another      */
  1715.                            /* duplicated keyword, bypass this keyword.       */
  1716.                            TmpPtr = &DKWTbl[MTNum][0];
  1717.                            do {
  1718.                               if (!memcmp(Tok,TmpPtr,TokLen)){
  1719.                                  continue;
  1720.                               }
  1721.                            }
  1722.                            while((TmpPtr=(char **)*(TmpPtr+3)) != NULL);
  1723.                            CurEvenOH = OH;
  1724.                            SavEPat = CurPat;
  1725.                            SavTok = Tok;
  1726.                            SavEIdx = j;
  1727.                            FndALOGKeyWrd = 1;
  1728.                         }
  1729.                      }
  1730.                   }
  1731.                }
  1732.             }
  1733.             /* Now that we're finished finding the even subpattern with the  */
  1734.             /* least overhead in the token, now find the same thing for the  */
  1735.             /* odd subpat in the same token.                                 */
  1736.             if (FndALOGKeyWrd) {
  1737.                FndALOGKeyWrd = 0;
  1738.                for (j=1; j<TokLen-1; j=j+2) {
  1739.                   CurPat = (Tok[j] << 8) | Tok[j+1];
  1740.                   if ((CurPat == SavEPat) && (i == 1)) {
  1741.                      /* dont allow article separator 2 use duplicate keywrds */
  1742.                      continue;
  1743.                   }
  1744.                   if (((MTNum = SubPat[CurPat]) == 0) && (i < 128)) {
  1745.                      if ((OH = SubPatFreq(CurPat)*T1) < CurOddOH) {
  1746.                         CurOddOH = OH;
  1747.                         SavOPat = CurPat;
  1748.                         SavOIdx = j;
  1749.                         FndALOGKeyWrd = 1;
  1750.                      }
  1751.                   }
  1752.                   else {
  1753.                      if (MTNum > 5) {    /* Not Article separator or End Of Buf */
  1754.                         if ( DsplTb[MTNum] != 0) {
  1755.                            if ((OH = SubPatFreq(CurPat)*T1) < CurOddOH) {
  1756.                               /* if token is identical to token currently in */
  1757.                               /* keyword table, bypass this keyword.         */
  1758.                               if (!memcmp(Tok,SvTbl[MTNum],TokLen)){
  1759.                                  continue;
  1760.                               }
  1761.                               CurOddOH = OH;
  1762.                               SavOPat = CurPat;
  1763.                               SavOIdx = j;
  1764.                               FndALOGKeyWrd = 1;
  1765.                            }
  1766.                         }
  1767.                         else {
  1768.                            NumDup = 1;
  1769.                            TmpPtr = &DKWTbl[MTNum][3];
  1770.                            /* Find number of duplicated subpatterns */
  1771.                            while((TmpPtr=(char **)*(TmpPtr+3)) != NULL) {
  1772.                               NumDup++;
  1773.                            }
  1774.                            if( (NumDup+1) << ((1<<29)/1000000/T3) ) {
  1775.                               MulFct = T2 + ((NumDup+1)*T3);
  1776.                            }
  1777.                            else {
  1778.                               MulFct = (1<<29)/1000000/T3 + NumDup;
  1779.                            }
  1780.                            if ((OH = SubPatFreq(CurPat)*MulFct) < CurOddOH) {
  1781.                               /* if token is identical to token of another   */
  1782.                               /* duplicated keyword, bypass this keyword.    */
  1783.                               TmpPtr = &DKWTbl[MTNum][0];
  1784.                               do {
  1785.                                  if (!memcmp(Tok,TmpPtr,TokLen)){
  1786.                                     continue;
  1787.                                  }
  1788.                               }
  1789.                               while((TmpPtr=(char **)*(TmpPtr+3)) != NULL);
  1790.                               CurOddOH = OH;
  1791.                               SavOPat = CurPat;
  1792.                               SavOIdx = j;
  1793.                               FndALOGKeyWrd = 1;
  1794.                            }
  1795.                         }
  1796.                      }
  1797.                   }
  1798.                }
  1799.             }
  1800.             /* If the total minimum overhead for the current token is less   */
  1801.             /* than that of the previously computed tokens then save that    */
  1802.             /* tokens info.                                                  */
  1803.             if ((CurEvenOH + CurOddOH < TotOH) && FndALOGKeyWrd) {
  1804.                /* Total overhead in usec for 20000 characters searched       */
  1805.                TotOH = CurEvenOH + CurOddOH;
  1806.                SavTOPat = SavOPat; /* Even SubPat with least overhead */
  1807.                SavTEPat = SavEPat; /* Odd SubPat with least overhead  */
  1808.                SavTOIdx = SavOIdx; /* Index into token of odd SubPat  */
  1809.                SavTEIdx = SavEIdx; /* Index into token of even SubPat */
  1810.                /* pntr to start of best token(not subpat) in MT */
  1811.                SavTTok = SavTok;
  1812. #ifdef DEBUG
  1813.                printf("MT %d has best even subpat of %c %c\n",NextMT,
  1814.                   SavTTok[SavTEIdx], SavTTok[SavTEIdx+1]);
  1815.                printf("MT %d has best odd subpat of %c %c\n",NextMT,
  1816.                   SavTTok[SavTOIdx], SavTTok[SavTOIdx+1]);
  1817. #endif
  1818.             }
  1819.          }
  1820.          else {
  1821.             if(TokLen == 2 && NextMT > 2 ) {   /* SubPat must have > 1 chars */
  1822.                /* Handle 2 character sub patterns. Dont allow duplicate      */
  1823.                /* keyword chaining, for now.                                 */
  1824.                CurOddOH = 2147483647;          /* Init to max pos overhead   */
  1825.                CurEvenOH = 2147483647;
  1826.                FndALOGKeyWrd = 0; /* Fnd At Least One Good Key Word in token */
  1827.                CurPat = (Tok[0] << 8) | Tok[1];     /* Construct test subpat */
  1828.                /* If SubPat table does not yet have an entry for CurPat,     */
  1829.                /* and if the limit of 128 Odd and 128 Even SubPats has not   */
  1830.                /* been reached, then compute the overhead for CurPat and if  */
  1831.                /* less than the previous smallest SubPat overhead(for this   */
  1832.                /* token) then save pointers to CurPat.                       */
  1833.                if ((SubPat[CurPat] == 0) && (i < 128)) {
  1834.                   CurEvenOH = SubPatFreq(CurPat)*T1;
  1835.                   SavEPat = CurPat;
  1836.                   SavTok = Tok;
  1837.                   SavEIdx = 0;
  1838.                   FndALOGKeyWrd = 1;
  1839.                }
  1840.                if (FndALOGKeyWrd) {
  1841.                   for( j=0; j<256; j++ ) {
  1842.                      CurPat = (Tok[1] << 8) | j;
  1843.                      if( (CurPat == SavEPat) || (i >= 128)
  1844.                         || (SubPat[CurPat] != 0) )  FndALOGKeyWrd = 0;
  1845.                   }
  1846.                   if( FndALOGKeyWrd == 1 ) {
  1847.                      CurPat = ((CurPat>>8) << 8) | 0x41;
  1848.                      CurOddOH = 1000000000 + SubPatFreq(CurPat)*T1;
  1849.                      SavOPat = CurPat;
  1850.                      SavOIdx = 1;
  1851.                   }
  1852.                   FndX = 1;
  1853.                   for( j=0; j<256; j++ ) {
  1854.                      CurPat = Tok[0] | j<<8;
  1855.                      if( (CurPat == SavEPat) || (i >= 128)
  1856.                         || (SubPat[CurPat] != 0) )  FndX = 0;
  1857.                   }
  1858.                   if( FndX == 1 && !TwoCharArtSep) {
  1859.                      CurPat = (CurPat & 255) | 0x41<<8;
  1860.                      if( 1000000000 + SubPatFreq(CurPat)*T1 < CurOddOH ) {
  1861.                         CurOddOH = 1000000000 + SubPatFreq(CurPat)*T1;
  1862.                         SavOPat = CurPat;
  1863.                         SavOIdx = -1;
  1864.                         FndALOGKeyWrd = 1;
  1865.                      }
  1866.                   }
  1867.                }
  1868.                /* If the total minimum overhead for the current token is less   */
  1869.                /* than that of the previously computed tokens then save that    */
  1870.                /* tokens info.                                                  */
  1871.                if ((CurEvenOH + CurOddOH < TotOH) && FndALOGKeyWrd) {
  1872.                   /* Total overhead in usec for 20000 characters searched       */
  1873.                   TotOH = CurEvenOH + CurOddOH;
  1874.                   SavTOPat = SavOPat; /* Even SubPat with least overhead */
  1875.                   SavTEPat = SavEPat; /* Odd SubPat with least overhead  */
  1876.                   SavTOIdx = SavOIdx; /* Index into token of odd SubPat  */
  1877.                   SavTEIdx = SavEIdx; /* Index into token of even SubPat */
  1878.                   /* pntr to start of best token(not subpat) in MT */
  1879.                   SavTTok = SavTok;
  1880. #ifdef DEBUG
  1881.                   printf("MT %d has best even subpat of %c %c\n",NextMT,
  1882.                      SavTTok[SavTEIdx], SavTTok[SavTEIdx+1]);
  1883.                   printf("MT %d has best odd subpat of %c %c\n",NextMT,
  1884.                      SavTTok[SavTOIdx], SavTTok[SavTOIdx+1]);
  1885. #endif
  1886.                }
  1887.             }
  1888.          }
  1889.          Tok = strtok( NULL, "?&*["); /* Get next token of MT to look at     */
  1890.       }
  1891.       Tok = SavTTok;
  1892.       /* If we have found the best odd and even SubPat of the MT, then put   */
  1893.       /* the SubPats in the various tables for faster searching later.       */
  1894.       if (TotOH != 2147483647) {       /* Have indeed found the best SubPats */
  1895.          /* 1st do even SubPat */
  1896.          if ((MTNum = SubPat[SavTEPat]) == 0) {   /* Non duplicated keyword  */
  1897.             MTN = SubPat[SavTEPat] = NextMT<<1;  /* Need to use              */
  1898.                                       /* MTNumSortedByKeyLen[SubPat(x)] to   */
  1899.                                       /* find Major Term Number later.       */
  1900.             frstuppr = toupper(SavTEPat >> 8);
  1901.             scnduppr = toupper(SavTEPat & 255);
  1902.             SubPat[(frstuppr*256) + (SavTEPat&255)] = MTN;
  1903.             SubPat[(SavTEPat&0xFF00) + scnduppr]  = MTN;
  1904.             SubPat[(frstuppr*256) + scnduppr]     = MTN;
  1905.             TokStrt[MTN] = Tok - (char *)&NoBrakArray[NextMT];
  1906.             TokEnd[MTN] = TokStrt[MTN] + strlen(Tok) - 1;
  1907.             if (SavTEIdx == 0) {  /* SubPat is 1st 2 chars of keyword(token) */
  1908.                if (strlen(Tok) < 4) {        /* Keyword is 2 or 3 chars long */
  1909.                   KWTbl[MTN][0] = Tok + 3; /* Pntr to start of rest of keywrd*/
  1910.                   KWTbl[MTN][1] = Tok + 2; /* Pntr to end of rest of keyword */
  1911.                   if( strlen(Tok) == 3 ) {        /* Keyword is 3 chars long */
  1912.                      FrstBt[MTN] = Tok[1];    /* 1st byte of rest of keyword */
  1913.                      ScndBt[MTN] = Tok[2];    /* 2nd byte of rest of keyword */
  1914.                      /* Displacemnt 2 where "rest of keywrd" should b in buf */
  1915.                      DsplTb[MTN] = 128 - 1 + 0;
  1916.                   }
  1917.                   else {
  1918.                      FrstBt[MTN] = Tok[0];    /* 1st byte of rest of keyword */
  1919.                      ScndBt[MTN] = Tok[1];    /* 2nd byte of rest of keyword */
  1920.                      /* Displacemnt 2 where "rest of keywrd" should b in buf */
  1921.                      DsplTb[MTN] = 128 - 2 + 0;
  1922.                   }
  1923.                   SvTbl[MTN] = Tok;
  1924.                   /* Displacement to start of keyword in buffer */
  1925.                   FDsplTbl[MTN] = -2;
  1926.                }
  1927.                else {
  1928.                   KWTbl[MTN][0] = Tok + 4;
  1929.                   KWTbl[MTN][1] = Tok + strlen(Tok) - 1;
  1930.                   FrstBt[MTN] = Tok[2];
  1931.                   ScndBt[MTN] = Tok[3];
  1932.                   DsplTb[MTN] = 128 - 0 + 0;
  1933.                   SvTbl[MTN] = Tok;
  1934.                   FDsplTbl[MTN] = -2;
  1935.                }
  1936.             }
  1937.             else {
  1938.                KWTbl[MTN][0] = Tok + 2;  /* Pntr to start of rest of keyword */
  1939.                KWTbl[MTN][1] = Tok + strlen(Tok) - 1;
  1940.                FrstBt[MTN] = Tok[0];
  1941.                ScndBt[MTN] = Tok[1];
  1942.                DsplTb[MTN] = 128 - 2 - SavTEIdx;
  1943.                SvTbl[MTN] = Tok;
  1944.                FDsplTbl[MTN] = - SavTEIdx - 2;
  1945.             }
  1946.             if (MTN < 6) {
  1947.                DsplTb[MTN] = 0;  /* EOB or article separator    */
  1948.                if (MTN == 2 || MTN == 3) {
  1949.                   DFASep[0] = 128 - 2 - SavTEIdx;
  1950.                }
  1951.             }
  1952.          }
  1953.          else { /* Duplicated keyword(more than 1 keyword for 1 subpattern)  */
  1954.             MTN = SubPat[SavTEPat];   /* Need to use                         */
  1955.                                       /* MTNumSortedByKeyLen[SubPat(x)] to   */
  1956.                                       /* find Major Term Number later.       */
  1957.             DKWIdx = NextMT << 1;
  1958.             TokStrt[DKWIdx] = Tok - (char *)&NoBrakArray[NextMT];
  1959.             TokEnd[DKWIdx] = TokStrt[DKWIdx] + strlen(Tok) - 1;
  1960.             if (DsplTb[MTN] != 0) {           /* Non Duplicated single entry */
  1961.                /* 1st remove the single entry and put it in the dupl tble    */
  1962.                /* then put the new element in the dupl table also            */
  1963.                DsplTb[MTN] = 0;   /* Adding 2nd keyword that has same subpat */
  1964.                DKWTbl[MTN][0] = SvTbl[MTN];    /* Pntr 2 strt of rest of kwd */
  1965.                DKWTbl[MTN][1] = KWTbl[MTN][1]; /* Pntr 2 end of rest of kwd  */
  1966.                DKWTbl[MTN][2] = (char *)FDsplTbl[MTN] + 128;
  1967.                DKWTbl[MTN][3] = (char *)&DKWTbl[DKWIdx];
  1968.                DKWTbl[DKWIdx][0] = Tok; /* Pointer 2 strt of rest of keyword */
  1969.                DKWTbl[DKWIdx][1] = Tok + strlen(Tok) - 1;  /* Pntr to end kw */
  1970.                DKWTbl[DKWIdx][2] = (char *)(128 - 2 - SavTEIdx); /* Displace */
  1971.                DKWTbl[DKWIdx][3] = NULL;                     /* link to next */
  1972.                FDsplTbl[DKWIdx] = - SavTEIdx - 2;
  1973.             }
  1974.             else { /* Duplicated entry */
  1975.                /* Put another duplicated entry in the dup keyword table      */
  1976.                TmpPtr = &DKWTbl[MTN][0];
  1977.                while((TmpPtr=(char **)*(TmpPtr+3)) != NULL) { MTTmp = TmpPtr; }
  1978.                *(MTTmp+3) = (char *)&DKWTbl[DKWIdx];
  1979.                DKWTbl[DKWIdx][0] = Tok; /* Pointer 2 strt of rest of keyword */
  1980.                DKWTbl[DKWIdx][1] = Tok + strlen(Tok) - 1;  /* Pntr to end kw */
  1981.                DKWTbl[DKWIdx][2] = (char *)(128 - 2 - SavTEIdx); /* Displace */
  1982.                DKWTbl[DKWIdx][3] = NULL;                     /* link to next */
  1983.                FDsplTbl[DKWIdx] = - SavTEIdx - 2;
  1984.             }
  1985.          }
  1986.          /* Now put stuff from odd SubPat into various tables */
  1987.          if ((MTNum = SubPat[SavTOPat]) == 0) {
  1988.             if( strlen(SavTTok) > 2 ) {
  1989.                MTN = SubPat[SavTOPat] = (NextMT<<1)+1;  /* Need to use       */
  1990.                                          /* MTNumSortedByKeyLen[SubPat(x)] to*/
  1991.                                          /* find Major Term Number later.    */
  1992.                frstuppr = toupper(SavTOPat >> 8);
  1993.                scnduppr = toupper(SavTOPat & 255);
  1994.                SubPat[(frstuppr*256) + (SavTOPat&255)] = MTN;
  1995.                SubPat[(SavTOPat&0xFF00) + scnduppr]  = MTN;
  1996.                SubPat[(frstuppr*256) + scnduppr]     = MTN;
  1997.                TokStrt[MTN] = Tok - (char *)&NoBrakArray[NextMT];
  1998.                TokEnd[MTN] = TokStrt[MTN] + strlen(Tok) - 1;
  1999.                KWTbl[MTN][0] = Tok + 2;   /* Pntr to strt of rest of keyword */
  2000.                if (strlen(Tok) == 3) {
  2001.                   /* Set to less than pntr 2 start so nothing chckd, since it*/
  2002.                   KWTbl[MTN][1] = Tok;  /* should already have been verified */
  2003.                }
  2004.                else {
  2005.                   KWTbl[MTN][1] = Tok + strlen(Tok) - 1;  /* Pntr 2 rest kwd */
  2006.                }
  2007.                FrstBt[MTN] = Tok[0];          /* 1st byte of rest of keyword */
  2008.                ScndBt[MTN] = Tok[1];          /* 2nd byte of rest of keyword */
  2009.                /* Displacement to where "rest of keywrd" should be in buffer */
  2010.                DsplTb[MTN] = 128 - 2 - SavTOIdx;
  2011.                SvTbl[MTN] = Tok;
  2012.                FDsplTbl[MTN] = - SavTOIdx - 2;
  2013.                if (MTN < 6) {
  2014.                   DsplTb[MTN] = 0;  /* EOB or article separator    */
  2015.                   if (MTN == 2 || MTN == 3) {
  2016.                      DFASep[1] = 128 - 2 - SavTOIdx;
  2017.                   }
  2018.                }
  2019.             }
  2020.             else {
  2021.                MTN = (NextMT<<1)+1;
  2022.                for( iij = 0; iij < 256; iij++ ) {
  2023.                   if( SavTOIdx == -1 ) {
  2024.                      CurPat = (SavTOPat & 255) | iij<<8;
  2025.                   }
  2026.                   else {
  2027.                      CurPat = ((SavTOPat>>8)<<8) | iij;
  2028.                   }
  2029.                   SubPat[CurPat] = MTN;
  2030.                   frstuppr = toupper(CurPat >> 8);
  2031.                   scnduppr = toupper(CurPat & 255);
  2032.                   SubPat[(frstuppr*256) + (CurPat&255)] = MTN;
  2033.                   SubPat[(CurPat&0xFF00) + scnduppr]    = MTN;
  2034.                   SubPat[(frstuppr*256) + scnduppr]     = MTN;
  2035.                }
  2036.                TokStrt[MTN] = Tok - (char *)&NoBrakArray[NextMT];
  2037.                TokEnd[MTN] = TokStrt[MTN] + strlen(Tok) - 1;
  2038.                KWTbl[MTN][0] = Tok+1;  /* Pntr to strt of rest of keyword    */
  2039.                /* Set to less than pntr 2 start so nothing chckd, since it   */
  2040.                KWTbl[MTN][1] = Tok;  /* should already have been verified    */
  2041.                FrstBt[MTN] = (char)(SavTEPat>>8); /* 1st byteofrestof keywrd */
  2042.                ScndBt[MTN] = (char)SavTEPat;  /* 2nd byte of rest of keyword */
  2043.                /* Displacement to where "rest of keywrd" should be in buf    */
  2044.                DsplTb[MTN] = 128 - 2 - SavTOIdx;
  2045.                SvTbl[MTN] = Tok;
  2046.                FDsplTbl[MTN] = - 2 - SavTOIdx;
  2047.             }
  2048.          }
  2049.          else { /* Duplicated keyword(more than 1 keyword for 1 subpattern)  */
  2050.             MTN = SubPat[SavTOPat];   /* Need to use                         */
  2051.                                       /* MTNumSortedByKeyLen[SubPat(x)] to   */
  2052.                                       /* find Major Term Number later.       */
  2053.             DKWIdx = (NextMT << 1) + 1;
  2054.             TokStrt[DKWIdx] = Tok - (char *)&NoBrakArray[NextMT];
  2055.             TokEnd[DKWIdx] = TokStrt[DKWIdx] + strlen(Tok) - 1;
  2056.             if (DsplTb[MTN] != 0) { /* Non Duplicated single entry */
  2057.                /* 1st remove the single entry and put it in the dupl tble    */
  2058.                /* then put the new element in the dupl table also            */
  2059.                DsplTb[MTN] = 0;   /* Adding 2nd keyword that has same subpat */
  2060.                DKWTbl[MTN][0] = SvTbl[MTN];    /* Pntr 2 strt of rest of kwd */
  2061.                DKWTbl[MTN][1] = KWTbl[MTN][1]; /* Pntr 2 end of rest of kwd  */
  2062.                DKWTbl[MTN][2] = (char *)FDsplTbl[MTN] + 128;
  2063.                DKWTbl[MTN][3] = (char *)&DKWTbl[DKWIdx];
  2064.                DKWTbl[DKWIdx][0] = Tok; /* Pointer 2 strt of rest of keyword */
  2065.                DKWTbl[DKWIdx][1] = Tok + strlen(Tok) - 1;  /* Pntr to end kw */
  2066.                DKWTbl[DKWIdx][2] = (char *)(128 - 2 - SavTOIdx); /* Displace */
  2067.                DKWTbl[DKWIdx][3] = NULL;                     /* link to next */
  2068.                FDsplTbl[DKWIdx] = - SavTOIdx - 2;
  2069.             }
  2070.             else { /* Duplicated entry */
  2071.                /* Put another duplicated entry in the dup keyword table      */
  2072.                TmpPtr = &DKWTbl[MTN][0];
  2073.                while((TmpPtr=(char **)*(TmpPtr+3)) != NULL) {MTTmp = TmpPtr;}
  2074.                *(MTTmp+3) = (char *)&DKWTbl[DKWIdx];
  2075.                DKWTbl[DKWIdx][0] = Tok; /* Pointer 2 strt of rest of keyword */
  2076.                DKWTbl[DKWIdx][1] = Tok + strlen(Tok) - 1;  /* Pntr to end kw */
  2077.                DKWTbl[DKWIdx][2] = (char *)(128 - 2 - SavTOIdx); /* Displace */
  2078.                DKWTbl[DKWIdx][3] = NULL;                     /* link to next */
  2079.                FDsplTbl[DKWIdx] = - SavTOIdx - 2;
  2080.             }
  2081.          }
  2082.       }
  2083.       /* Could not find at least one good keyword in all the tokens of a     */
  2084.       /* major term. A good keyword has at least one set of unique even and  */
  2085.       /* odd 2 char subpats and the keyword must not be the same as any      */
  2086.       /* other keyword already in the table that has the same subpat.        */
  2087.       /* For right now, print out an error and exit. Needs to be handled     */
  2088.       /* better later. This should not happen very often at all.             */
  2089.       else {
  2090.          if(i==1) {
  2091.             fprintf(stderr,"Article separators must have at least 2 unique\n");
  2092.             fprintf(stderr,"characters. Try adding a \\n or space to it.\n");
  2093.             ErrP("Aborting...\n");
  2094.          }
  2095.          else {
  2096.             fprintf(stderr,"For search pattern %s, didn't\n",
  2097.                     &MTArray[NextMT-1]);
  2098.             fprintf(stderr,"find a unique even & odd 2 char subpat. MT=%d.\n",
  2099.                     NextMT);
  2100.             fprintf(stderr,"Try adding a unique char to search pattern.\n");
  2101.             ErrP("Aborting...\n");
  2102.          }
  2103.       }
  2104.    }
  2105.    /* if article separator is only two char long, reset its end pointer back */
  2106.    /* back to what it originally was. Also copy subpat table value for the   */
  2107.    /* 0x20 prefix to all other possible prefixes.                            */
  2108.    if( TwoCharArtSep ) {
  2109.       EOASep--;
  2110.       *(ArtSep + 2) = 0x00;
  2111.       SPIdx = *(ArtSep + 1) << 8;
  2112.       for( iij = 0; iij < 256; iij++ ) {
  2113.          if( SubPat[SPIdx + iij] == 0 ) {
  2114.             SubPat[SPIdx + iij] = 3;
  2115.          }
  2116.          else {
  2117.             if( SubPat[SPIdx + iij] > 3 ) {
  2118.                fprintf(stderr,"\nOdd Art sep srch pat(hex): %lx",SPIdx+iij);
  2119.                if( SubPat[SPIdx+iij] & 1 == 1 ) {
  2120.                   fprintf(stderr,"\nThe odd part(don't care) of the following "
  2121.                                  "srch pat conflicts(hex): %lx",
  2122.                                  *(short *)SvTbl[SubPat[SPIdx+iij]] );
  2123.                }
  2124.                else {
  2125.                   fprintf(stderr,"\nEven srch pat that conflicts is(hex): %lx",
  2126.                                  *SvTbl[SubPat[SPIdx+iij]] );
  2127.                }
  2128.                fprintf(stderr,"\nSrch pat is in major term %d\n",
  2129.                               (unsigned int)(SubPat[SPIdx+iij] >> 1));
  2130.                ErrP("Err:Try adding another char to conflicting srch pat.\n");
  2131.             }
  2132.          }
  2133.       }
  2134.    }
  2135.    LastInLast = 0;
  2136.    LastPntEnd = NULL;
  2137.    /* default start of article so nothing bad will happen if there are no    */
  2138.    /* article separators in the file                                         */
  2139.    CurArtStrt = BufIdx;
  2140.  
  2141. /*   StrtTime = clock(); */
  2142.    while (1==1) {
  2143.       MTIdx = FastSearch(BufIdx);
  2144.       MTNum = MTIdx >> 1;
  2145.       if (MTIdx > 5) {
  2146. /* Since keyword was found, need to make sure the rest of the major term */
  2147. /* matches also, before declaring major term satisfied.                  */
  2148.          if (!OutArt && FindRestOfMT(BufIdx, MTIdx)) {
  2149.             if (!MinSatByMTOnly[MTNum] && !LineScan)  {
  2150. /* Set bit indicating MT satisfied.                                      */
  2151.                TmpT = MajTrm2BitNum[MTNum];
  2152.                MinSatTbl[MajTrm2MinTrm[MTNum]][1] |= 1 << TmpT;
  2153. /* Since major term was satisfied, need to check MinSatTbl to see if     */
  2154. /* minterm is fully satisfied.                                           */
  2155.                Indx = MajTrm2MinTrm[ MTNum];
  2156.                if ((MinSatTbl[Indx][0] | MinSatTbl[Indx][1]) == -1 )  {
  2157. /* Since minterm was satisfied, we set a flag "OutArt" so that when next */
  2158. /* article separator or "End of Data" is encountered, the article will   */
  2159. /* be printed out.                                                       */
  2160.                   OutArt = 1;
  2161.                }
  2162. /* Add major term to chain of those needing to be reset at "End Of Article" */
  2163. /* First check for loop. Loop is when a maj trm occured more than once      */
  2164. /* in the article.                                                          */
  2165.                if (!LastMTTbl[ MTNum] && (MTNum != LastMT)) {
  2166.                   LastMTTbl[ LastMT] = MTNum;
  2167.                   LastMT = MTNum;
  2168.                }
  2169.             }
  2170. /* Comes here if only 1 maj term needs to be satisfied for minterm to be */
  2171. /* satisfied. In this case, set flag to print out article at next EOA.   */
  2172. /* Also comes here if the Line Scan flag is set.                         */
  2173.             else {
  2174.                if (LineScan) {
  2175.                   PathPrint(MatchFnd);
  2176.                   /* if match found in overlapped portion at end of buffer,*/
  2177.                   /* set next overlap size so the match will not be found  */
  2178.                   /* again once the new buffer is switched to.             */
  2179.  
  2180.                   if( EOCB - BufIdx < MAXKWSZ) KeyWrdOvlp = EOCB - BufIdx;
  2181.  
  2182.                   /* Find start of word with match in it for delayed print */
  2183.                   /* This is needed so that the front part of the matched  */
  2184.                   /* word will be highlighted when right context from the  */
  2185.                   /* previous match overlaps this match. The front would   */
  2186.                   /* not normally be highlighted if the two char keyword   */
  2187.                   /* does not occur at the start of the matched word.      */
  2188.                   KeyStrt = BufIdx + FDsplTbl[MTIdx];
  2189.                   WrdStrt = KeyStrt - 1;
  2190.                   while( isalnum((int)(*WrdStrt)) && WrdStrt >= SOCB) {
  2191.                      WrdStrt--;
  2192.                   }
  2193.                   WrdStrt++;
  2194.                   if( KeyStrt - WrdStrt > 256 ) WrdStrt = KeyStrt - 256;
  2195.                   SizeDiff = KeyStrt - WrdStrt;
  2196.                   if( DlydPntNextBuf ) {
  2197. /* Comes here if the right context from the previous match overlapped two  */
  2198. /* buffers. The part in the previous buffer has been printed out already.  */
  2199. /* Determine where the right context stops in pres buf by counting line    */
  2200. /* feeds.                                                                  */
  2201.                      DlydPntNextBuf = 0;
  2202.                      PntPtr = SOCB;
  2203.                      StrtLFC = LFCnt - 1;
  2204.                      while((PntPtr < EOCB) && (LFCnt <= PrntWidth)) {
  2205.                         if(*PntPtr == '\n') { LFCnt++; }
  2206.                         if( PntPtr - SOCB > 256 * (LFCnt - StrtLFC) ) {
  2207.                            LFCnt = PrntWidth + 1;
  2208.                            CutIt = 1;
  2209.                         }
  2210.                         PntPtr++;
  2211.                      }
  2212.                      DlydPntStart = SOCB;
  2213.                      DlydPntSize  = PntPtr - SOCB;
  2214.                      DlydPntRightContext = 1;
  2215.                      LastInLast = 0; /* 1st print in pres buf */
  2216.                   }
  2217.                   DlydPntEnd = DlydPntStart + DlydPntSize;
  2218.                   if( DlydPntRightContext && DlydPntEnd < WrdStrt) {
  2219. /* Comes here if we know that the right context from the previous match  */
  2220. /* does not extend up to the present match. Print it out.                */
  2221.                      fxwrite(DlydPntStart,BlkSize,DlydPntSize,StrmPtr,NoKeyW);
  2222.                      DlydPntRightContext = 0;
  2223.                      RightStrt = DlydPntEnd;
  2224.                      LastPntEnd = DlydPntEnd - 1;
  2225.                   }
  2226.                   if( DlydPntRightContext && DlydPntEnd >= WrdStrt) {
  2227. /* Comes here if we know that the right context from the previous match  */
  2228. /* extends all the way to the present match, and farther. Chop it off so */
  2229. /* it only extends up to the start of the present matched word and print */
  2230. /* the context.                                                          */
  2231.                      DlydPntRightContext = 0;
  2232.                      DlydPntSize = WrdStrt - DlydPntStart;
  2233.                      if( DlydPntSize < 0 ) {
  2234.                         fxwrite(DlydPntStart,BlkSize,ZeroLong,StrmPtr,NoKeyW);
  2235.                         NumBlksToWrt = TokEnd[MTIdx] - TokStrt[MTIdx] + 1 +
  2236.                                        SizeDiff + DlydPntSize;
  2237.                         RightStrt = DlydPntStart + NumBlksToWrt;
  2238.                         TotTokLen = TokEnd[MTIdx] - TokStrt[MTIdx] + 1;
  2239. /* Now print out matched word with keyword in it for present match       */
  2240.                         fxwrite(DlydPntStart,BlkSize,NumBlksToWrt,StrmPtr,HasKeyWrd);
  2241.                      }
  2242.                      else {
  2243.                         /* print stuff between last and present match */
  2244.                         fxwrite(DlydPntStart,BlkSize,DlydPntSize,StrmPtr,NoKeyW);
  2245.                         NumBlksToWrt = TokEnd[MTIdx] - TokStrt[MTIdx] + 1 +
  2246.                                        SizeDiff;
  2247.                         RightStrt = WrdStrt + NumBlksToWrt;
  2248.                         TotTokLen = TokEnd[MTIdx] - TokStrt[MTIdx] + 1;
  2249. /* Now print out matched word with keyword in it for present match       */
  2250.                         fxwrite(WrdStrt,BlkSize,NumBlksToWrt,StrmPtr,HasKeyWrd);
  2251.                      }
  2252.                   }
  2253.                   else {
  2254. /* Print out plus and minus PrntWidth lines around match.                */
  2255.                      FrstPnt = 1;
  2256.                      LFCnt = 0;
  2257.                      StrtLFC = LFCnt - 1;
  2258.                      PntPtr = BufIdx + FDsplTbl[MTIdx] - 1;
  2259.                      StrtPP = PntPtr;
  2260.                      while((PntPtr >= SOCB) && (LFCnt <= PrntWidth) &&
  2261.                           ((PntPtr > LastPntEnd) || LastInLast)) {
  2262.                         if(*PntPtr == '\n') { LFCnt++; }
  2263.                         if( StrtPP - PntPtr > 256 * (LFCnt - StrtLFC) )
  2264.                            LFCnt = PrntWidth + 1;
  2265.                         PntPtr--;
  2266.                      }
  2267. /* print out any context info in previous buffer                         */
  2268.                      if((PntPtr < SOCB) && (CurArtStrt != SOCB) &&
  2269.                               (LFCnt <= PrntWidth)) {
  2270.                         StrtLFC = LFCnt - 1;
  2271.                         PntPtr = EndOfPrevBuf + (PntPtr - SOCB);
  2272.                         StrtPP = PntPtr;
  2273.                         while((PntPtr >= CurArtStrt) && (LFCnt <= PrntWidth) &&
  2274.                              ((PntPtr > LastPntEnd) && LastInLast)) {
  2275.                            if(*PntPtr == '\n') { LFCnt++; }
  2276.                            if( StrtPP - PntPtr > 256 * (LFCnt - StrtLFC) )
  2277.                               LFCnt = PrntWidth + 1;
  2278.                            PntPtr--;
  2279.                         }
  2280.                         if(PntPtr + 1 < EndOfPrevBuf) {
  2281.                            NumBlksToWrt = EndOfPrevBuf - PntPtr - 1;
  2282.                            if(FrstPnt && (*(PntPtr+1) == '\n')) {
  2283.                               NumBlksToWrt--;
  2284.                               PntPtr++;
  2285.                               FrstPnt = 0;
  2286.                            }
  2287.                            if(NumBlksToWrt > 0) {
  2288.                               fywrite(PntPtr+1,BlkSize,NumBlksToWrt,StrmPtr);
  2289.                            }
  2290.                         }
  2291.                         PntPtr = SOCB - 1;
  2292.                         LastPntEnd = PntPtr;
  2293.                      }
  2294. /* print out context info in current buffer to the left of, and including */
  2295. /* the matched keyword.                                                   */
  2296.                      PntPtr++;
  2297.                      NumBlksToWrt = BufIdx + FDsplTbl[MTIdx] + TokEnd[MTIdx] -
  2298.                         TokStrt[MTIdx] - PntPtr + 1;
  2299.                      RightStrt = PntPtr + NumBlksToWrt;
  2300.                      if(PntPtr + NumBlksToWrt - 1 > LastPntEnd || LastInLast) {
  2301.                         if (!LastInLast && (PntPtr <= LastPntEnd)) {
  2302.                            PntPtr = LastPntEnd + 1;
  2303.                            NumBlksToWrt = RightStrt - PntPtr;
  2304.                         }
  2305.                         if(FrstPnt && (*PntPtr == '\n')) {
  2306.                            NumBlksToWrt--;
  2307.                            PntPtr++;
  2308.                            FrstPnt = 0;
  2309.                         }
  2310.                         if(NumBlksToWrt > 0) {
  2311.                            TotTokLen = TokEnd[MTIdx] - TokStrt[MTIdx] + 1;
  2312.                            fxwrite(PntPtr,BlkSize,NumBlksToWrt,StrmPtr,
  2313.                                                                HasKeyWrd);
  2314.                            RightStrt = PntPtr + NumBlksToWrt;
  2315.                         }
  2316.                      }
  2317.                   }
  2318.                   /* save pointer to last item printed to it wont be    */
  2319.                   /* printed again.                                     */
  2320.                   LastPntEnd = RightStrt - 1;
  2321. /* print out context info in the present buf, to the right of the matched  */
  2322. /* keyword.                                                                */
  2323.                   LFCnt = 0;
  2324.                   StrtLFC = -1;
  2325.                   PntPtr = RightStrt;
  2326.                   while((PntPtr < EOCB) && (LFCnt <= PrntWidth)) {
  2327.                      if(*PntPtr == '\n') { LFCnt++; }
  2328.                      if( PntPtr - RightStrt > 256 * (LFCnt - StrtLFC) ) {
  2329.                         LFCnt = PrntWidth + 1;
  2330.                         CutIt = 1;
  2331.                      }
  2332.                      PntPtr++;
  2333.                   }
  2334.                   NumBlksToWrt = PntPtr - RightStrt;
  2335.                   if( NumBlksToWrt > 0 || LastInLast || PntPtr==EOCB) {
  2336.                      /* Set flag so that when EOCB or next match is     */
  2337.                      /* found, right context will be printed out.       */
  2338.                      DlydPntRightContext = 1;
  2339.                      DlydPntStart = RightStrt;
  2340.                      DlydPntSize = NumBlksToWrt;
  2341.                   }
  2342.                   LastInLast = 0;
  2343.                }
  2344.                else {
  2345.                   OutArt = 1;
  2346.                }
  2347.             }
  2348.          }
  2349.       }
  2350.       else {
  2351.          if (MTIdx < 4) {    /* MT of 2 or 3 indicates article separator */
  2352. /* If flag is set specifying that article separator needs to be in a     */
  2353. /* certain column, then check for this.                                  */
  2354.             ColOk = 1;
  2355.             if (ColReq) {
  2356. /* if article separator is not in right column, reset ColOk to 0         */
  2357.                if( *(BufIdx + FDsplTbl[MTIdx] - ColReq) == '\n') {
  2358.                   TmpP = BufIdx + FDsplTbl[MTIdx];
  2359.                   for( BP=TmpP-ColReq+1; BP<TmpP; BP++) {
  2360.                      if( *BP == '\n') { ColOk = 0; break; }
  2361.                   }
  2362.                }
  2363.                else {
  2364.                   ColOk = 0;
  2365.                }
  2366.             }
  2367.             if (ColOk && !LineScan) {
  2368. /* If flag "OutArt" is set, then print out article                       */
  2369.                if (OutArt != InvertMatch) {
  2370.                   if( WroteOverIt ) {
  2371.                      fprintf(stderr,"Warning: Article was too long. Did "
  2372.                      "not print out front part of article.\n         Suggest"
  2373.                      " increasing window size if not LHA.\n");
  2374. /*                     if( !RealFile ) ErrP("Aborting...\n");            */
  2375.                   }
  2376.                   PathPrint(MatchFnd);
  2377.                   TmpCS2 = TmpCS = BufIdx + FDsplTbl[MTIdx];
  2378.                   /* if article sep is found in the middle of a line, back */
  2379.                   /* up until a line feed is found and use as strt of art. */
  2380.                   for( iii=TmpCS2; iii>TmpCS2-LWIDTH; iii--) {
  2381.                      if( *iii == '\n') { TmpCS = iii + 1; break; }
  2382.                   }
  2383.                   if( !PrntPrevPrev ) {
  2384.                      TmpCS2 = CurArtStrt;
  2385.                      /* if article sep is found in the middle of line, back */
  2386.                      /* up until line feed is found and use as strt of art. */
  2387.                      for( iii=TmpCS2; iii>TmpCS2-LWIDTH; iii--) {
  2388.                         if( *iii == '\n') { CurArtStrt = iii + 1; break; }
  2389.                      }
  2390.                   }
  2391.                   if (ArtInPrevBuf) {
  2392.                      /* take care of case where article sep is found at  */
  2393.                      /* the very end of previous buf and the same article*/
  2394.                      /* separator found before the start of current buf. */
  2395.                      NumBlksToWrt = EndOfPrevBuf - CurArtStrt;
  2396.                      NumBlksToWrt2 = TmpCS - SOCB;
  2397.                      if (NumBlksToWrt + NumBlksToWrt2 > MAXKWSZ) {
  2398.                         if (!RealFile) {
  2399.                            /* set all nonprinting chars to blanks */
  2400.                            for (iii=CurArtStrt; iii<EndOfPrevBuf; iii++) {
  2401.                               bufchr = (int)(*iii);
  2402.                               if (!isprint(bufchr) && *iii != '\n') *iii = ' ';
  2403.                            }
  2404.                         }
  2405.                         /* take care of case where article separator */
  2406.                         /* straddles the end of buffer.              */
  2407.                         if(NumBlksToWrt2 < 0){ NumBlksToWrt += NumBlksToWrt2; }
  2408.                         /* write out part of article in previous buffer */
  2409.                         fwrite(CurArtStrt,BlkSize,NumBlksToWrt,StrmPtr);
  2410.                      }
  2411.                      CurArtStrt = SOCB;
  2412.                   }
  2413.                   NumBlksToWrt = TmpCS - CurArtStrt;
  2414.                   if (!RealFile) {
  2415.                      /* set all nonprinting chars to blanks */
  2416.                      for (iii=CurArtStrt; iii<TmpCS; iii++) {
  2417.                         bufchr = (int)(*iii);
  2418.                         if (!isprint(bufchr) && *iii != '\n') {
  2419.                            *iii = ' ';
  2420.                         }
  2421.                      }
  2422.                   }
  2423.                   if (NumBlksToWrt > 0) {
  2424.                      fwrite(CurArtStrt,BlkSize,NumBlksToWrt,StrmPtr);
  2425.                   }
  2426.                }
  2427.                WroteOverIt = 0;
  2428.                PrntPrevPrev = 0;
  2429.                OutArt = 0;
  2430.                ArtInPrevBuf = 0;
  2431. /* Reset list of partially satisfied minterms since article separator    */
  2432. /* was found.                                                            */
  2433.                Indx = 0;
  2434.                while (MTIndx = LastMTTbl[ Indx]) {
  2435.                   TmpT = MajTrm2BitNum[MTIndx];
  2436.                   MinSatTbl[MajTrm2MinTrm[MTIndx]][1] ^= 1 << TmpT;
  2437.                   LastMTTbl[ Indx] = 0;
  2438.                   Indx = MTIndx;
  2439.                }
  2440.                LastMT = 0;
  2441. /* Mark start of article so if pattern is found in it, the whole article */
  2442. /* can be printed out                                                    */
  2443.                CurArtStrt = BufIdx + FDsplTbl[MTIdx];
  2444. /* If, over 5 articles, a few two-char subpatterns dominate(# of subpat  */
  2445. /* hits is > threshold), reselect a new two-char subpat for the          */
  2446. /* corresponding major terms.                                            */
  2447.             }
  2448.          }
  2449.          else {                              /* Must be at End Of Buffer */
  2450. /* Switch buffers since EOB found                                        */
  2451. /* Note that this could possibly be sped up if open on next file can     */
  2452. /* occur while last buffer of current file is scanned.                   */
  2453. /*            EndTime = clock();   */
  2454. /*            printf("time1= %lu and time2= %lu \n",StrtTime,EndTime); */
  2455. /*            TotTime += EndTime - StrtTime;  */
  2456.  
  2457.             /* If we had a match in the buffer before the buffer before the */
  2458.             /* one we are about to switch to, or earlier, print it out the  */
  2459.             /* previous buffers contents.                                   */
  2460.             if (ArtInPrevBuf) {
  2461.                if (OutArt != InvertMatch && !LineScan) {
  2462.                   PathPrint(MatchFnd);
  2463.                   if( WroteOverIt ) {
  2464.                      fprintf(stderr,"Warning: Article was too long. Did "
  2465.                      "not print out front part of article.\n         Suggest"
  2466.                      " increasing window size if not LHA.\n");
  2467. /*                     if( !RealFile ) ErrP("Aborting...\n");            */
  2468.                   }
  2469.                   if (!RealFile) {
  2470.                      /* set all nonprinting chars to blanks */
  2471.                      for (iii=CurArtStrt; iii<EndOfPrevBuf; iii++) {
  2472.                         bufchr = (int)(*iii);
  2473.                         if (!isprint(bufchr) && *iii != '\n') {
  2474.                            *iii = ' ';
  2475.                         }
  2476.                      }
  2477.                   }
  2478.                   NumBlksToWrt = EndOfPrevBuf - CurArtStrt;
  2479.                   fwrite(CurArtStrt,BlkSize,NumBlksToWrt,StrmPtr);
  2480.                }
  2481.                else {
  2482.                   WroteOverIt = 1;
  2483.                }
  2484. /* If "Start of Article" is in buffer being overwritten by async read,   */
  2485. /* set "Start of Article" to beginning of next buffer after one being    */
  2486. /* overwritten. This is the same as setting it to the start of the       */
  2487. /* buffer just finished being used.                                      */
  2488.                CurArtStrt = SOCB;
  2489.                PrntPrevPrev = 1;
  2490.             }
  2491.             else { ArtInPrevBuf = 1; }
  2492.             EndOfPrevBuf = EOCB;
  2493.             LastInLast = 1;
  2494.             if( DlydPntNextBuf ) {
  2495.                DlydPntNextBuf = 0;
  2496.                PntPtr = SOCB;
  2497.                StrtLFC = LFCnt - 1;
  2498.                while((PntPtr < EOCB) && (LFCnt <= PrntWidth)) {
  2499.                   if(*PntPtr == '\n') { LFCnt++; }
  2500.                   if( PntPtr - SOCB > 256 * (LFCnt - StrtLFC) ) {
  2501.                      LFCnt = PrntWidth + 1;
  2502.                      CutIt = 1;
  2503.                   }
  2504.                   PntPtr++;
  2505.                }
  2506.                DlydPntStart = SOCB;
  2507.                DlydPntSize  = PntPtr - SOCB;
  2508.                DlydPntRightContext = 1;
  2509.             }
  2510.             if( DlydPntRightContext) {
  2511.                /* print right context from previous match if line-scan */
  2512.                /* option set                                           */
  2513.                fxwrite(DlydPntStart,BlkSize,DlydPntSize,StrmPtr,NoKeyW);
  2514.                DlydPntRightContext = 0;
  2515.                if( LFCnt <= PrntWidth ) DlydPntNextBuf = 1;
  2516.                if( (DlydPntStart + DlydPntSize) == EOCB && *(EOCB-1) != '\n')
  2517.                   MayNeedLF = 1;
  2518.             }
  2519.             SavEOCB = EOCB;
  2520.             SavSOCB = SOCB;
  2521.             if( LineNum ) { CountCR(); }
  2522.             /* Note that on both normal, LZH archive files, and internal    */
  2523.             /* LZH archive files, an extra read of -1 bytes follows the     */
  2524.             /* last read of a nonzero # of bytes. When OpenNew is on return,*/
  2525.             /* it sets things up as if it did a read of zero bytes, even    */
  2526.             /* though it returns -1.                                        */
  2527.             if( xfrread(FHandle) <= 0 ) {
  2528.                KeyWrdOvlp = MAXKWSZ;
  2529.                if (OutArt != InvertMatch && !LineScan) {
  2530.                   PathPrint(MatchFnd);
  2531.                   if( !PrntPrevPrev ) {
  2532.                      TmpCS2 = CurArtStrt;
  2533.                      /* if article sep is found in the middle of line, back */
  2534.                      /* up until line feed is found and use as strt of art. */
  2535.                      for( iii=TmpCS2; iii>TmpCS2-LWIDTH; iii--) {
  2536.                         if( *iii == '\n') { CurArtStrt = iii + 1; break; }
  2537.                      }
  2538.                   }
  2539.                   NumBlksToWrt = EndOfPrevBuf - CurArtStrt;
  2540.                   if (!RealFile) {
  2541.                      /* set all nonprinting chars to blanks */
  2542.                      for (iii=CurArtStrt; iii<EndOfPrevBuf; iii++) {
  2543.                         bufchr = (int)(*iii);
  2544.                         if (!isprint(bufchr) && *iii != '\n') {
  2545.                            *iii = ' ';
  2546.                         }
  2547.                      }
  2548.                   }
  2549.                   fwrite(CurArtStrt,BlkSize,NumBlksToWrt,StrmPtr);
  2550.                }
  2551.  
  2552.                if( MayNeedLF ) { fwrite("\n",1,1,StrmPtr); MayNeedLF = 0; }
  2553.                if( !LON ) { /* if not doing an lzh or finished with lzh */
  2554.                   LON = 1;
  2555.                   xfrclose(FHandle);
  2556.                   if ((FName=NextFile(ArgVSav)) != NULL) {
  2557.                      if ((FHandle = xfropen(FName,&ReadNum)) == NULL) {
  2558.                         ErrP("Problems opening file to scan\n");
  2559.                      }
  2560.                      if (ReadNum < 0) {
  2561.                         ErrP("Could not read any data from file\n");
  2562.                      }
  2563.                   }
  2564.                   else {
  2565. /*                     printf("time1= %lu ;time2= %lu \n",StrtTime,EndTime);*/
  2566. /*                     EndTime = clock(); */
  2567. /*                     TotTime += EndTime - StrtTime; */
  2568. /*                   printf("total time(50ths of sec) = %lu\n",TotTime); */
  2569.                      if(!RealFile && AlwaysPrint && !Mtch1st) {
  2570.                         fwrite("\n",1,1,StrmPtr);
  2571.                      }
  2572.                      CleanIt();
  2573.                      exit(0); /* terminate normally */
  2574.                   }
  2575.                }
  2576.  
  2577. /*               StrtTime = clock(); */
  2578.                PathPrint(MatchNotFnd);
  2579.                NumOfCR = 0;
  2580.                NumTot = -1;
  2581.                LstOut = SOCB;
  2582.                OutArt = 0;
  2583.                ArtInPrevBuf = 0;
  2584.                PrntPrevPrev = 0;
  2585.                DlydPntNextBuf = 0;
  2586.                WroteOverIt = 0;
  2587.                LastInLast = 0;
  2588.                LastPntEnd = NULL;
  2589.                /* If inverted matching, set to not print out when 1st */
  2590.                /* article header found                                */
  2591.                if (InvertMatch) { OutArt = 1; }
  2592.                /* default start of article so nothing bad will happen */
  2593.                /* if there are no article separators in the file      */
  2594.                CurArtStrt = BufIdx;
  2595.                /* Reset list of partially satisfied minterms since    */
  2596.                /* article separator was found.                        */
  2597.                Indx = 0;
  2598.                while (MTIndx = LastMTTbl[ Indx]) {
  2599.                   TmpT = MajTrm2BitNum[MTIndx];
  2600.                   MinSatTbl[MajTrm2MinTrm[MTIndx]][1] ^= 1 << TmpT;
  2601.                   LastMTTbl[ Indx] = 0;
  2602.                   Indx = MTIndx;
  2603.                }
  2604.                LastMT = 0;
  2605.             }
  2606.             else {
  2607.                if( ItsALZH ) PathPrint(MatchNotFnd);
  2608.                LstOut = SOCB;
  2609.                MayNeedLF = 0;
  2610.             }
  2611.          }
  2612.       }
  2613.    }
  2614. }
  2615.