home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / agrep201 / part01 < prev    next >
Encoding:
Text File  |  1992-05-08  |  60.3 KB  |  1,843 lines

  1. Newsgroups: comp.sources.unix
  2. From: sw@cs.arizona.edu (Sun Wu)
  3. Subject: v26i021: agrep - very fast grep with approximate pattern matching, Part01/03
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: sw@cs.arizona.edu (Sun Wu)
  8. Posting-Number: Volume 26, Issue 21
  9. Archive-Name: agrep-2.01/part01
  10.  
  11. [ I've been using this since I got it, and it's GREAT.  Faster than gnugrep
  12.   and bmgrep almost always, and faster than egrep if you don't need the
  13.   extended regex syntax.                        --vix ]
  14.  
  15. This is version 2.01 of agrep - a new tool for fast text searching allowing
  16. errors.  agrep is similar to egrep/grep/fgrep, but it is much more general
  17. and usually faster.
  18.  
  19. The three most significant features of agrep that are not supported by
  20. the grep family are 
  21. 1) the ability to search for approximate patterns;
  22.     for example, "agrep -2 homogenos foo" will find homogeneous as well 
  23.     as any other word that can be obtained from homogenos with at most 
  24.     2 substitutions, insertions, or deletions.
  25.     "agrep -B homogenos foo" will generate a message of the form
  26.     best match has 2 errors, there are 5 matches, output them? (y/n)
  27. 2) agrep is record oriented rather than just line oriented;  a record
  28.     is by default a line, but it can be user defined;
  29.     for example, "agrep -d '^From ' 'pizza' mbox"
  30.     outputs all mail messages that contain the keyword "pizza".
  31.     Another example:  "agrep -d '$$' pattern foo" will output all
  32.     paragraphs (separated by an empty line) that contain pattern.
  33. 3) multiple patterns with AND (or OR) logic queries.   
  34.     For example, "agrep -d '^From ' 'burger,pizza' mbox" 
  35.     outputs all mail messages containing at least one of the 
  36.     two keywords (, stands for OR).
  37.     "agrep -d '^From ' 'good;pizza' mbox" outputs all mail messages
  38.     containing both keywords.
  39.  
  40. Putting these options together one can ask queries like
  41.  
  42. agrep -d '$$' -2 '<CACM>;TheAuthor;Curriculum;<198[5-9]>' bib
  43.  
  44. which outputs all paragraphs referencing articles in CACM between 
  45. 1985 and 1989 by TheAuthor dealing with curriculum.  
  46. Two errors are allowed, but they cannot be in either CACM or the year 
  47. (the <> brackets forbid errors in the pattern between them).  
  48.  
  49. Other features include searching for regular expressions (with or
  50. without errors), unlimited wild cards, limiting the errors to only 
  51. insertions or only substitutions or any combination, 
  52. allowing each deletion, for example, to be counted as, say, 
  53. 2 substitutions or 3 insertions, restricting parts of the query 
  54. to be exact and parts to be approximate, and many more.
  55.  
  56. Please mail bug reports (or any other comments) 
  57. to sw@cs.arizona.edu or to udi@cs.arizona.edu.
  58.  
  59. We would appreciate if users notify us (at the address above)
  60. of any extensions, improvements, or interesting uses of this software.
  61.  
  62. Feburary 23, 1992
  63.  
  64. #! /bin/sh
  65. # This is a shell archive.  Remove anything before this line, then unpack
  66. # it by saving it into a file and typing "sh file".  To overwrite existing
  67. # files, type "sh file -c".  You can also feed this as standard input via
  68. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  69. # will see the following message at the end:
  70. #        "End of archive 1 (of 3)."
  71. # Contents:  COPYRIGHT Makefile README agrep.algorithms agrep.chronicle
  72. #   agrep.h asearch1.c bitap.c checkfile.c checkfile.h compat.c
  73. #   contribution.list follow.c maskgen.c preprocess.c re.h utilities.c
  74. # Wrapped by sw@optima on Sun Feb 23 13:44:15 1992
  75. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  76. if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then 
  77.   echo shar: Will not clobber existing file \"'COPYRIGHT'\"
  78. else
  79. echo shar: Extracting \"'COPYRIGHT'\" \(971 characters\)
  80. sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE'
  81. This material was developed by Sun Wu and Udi Manber
  82. at the University of Arizona, Department of Computer Science.
  83. Permission is granted to copy this software, to redistribute it
  84. on a nonprofit basis, and to use it for any purpose, subject to
  85. the following restrictions and understandings.
  86. X
  87. X1. Any copy made of this software must include this copyright notice
  88. in full.
  89. X
  90. X2. All materials developed as a consequence of the use of this
  91. software shall duly acknowledge such use, in accordance with the usual
  92. standards of acknowledging credit in academic research.
  93. X
  94. X3. The authors have made no warranty or representation that the
  95. operation of this software will be error-free or suitable for any
  96. application, and they are under under no obligation to provide any
  97. services, by way of maintenance, update, or otherwise.  The software
  98. is an experimental prototype offered on an as-is basis.
  99. X
  100. X4. Redistribution for profit requires the express, written permission
  101. of the authors.
  102. X
  103. END_OF_FILE
  104. if test 971 -ne `wc -c <'COPYRIGHT'`; then
  105.     echo shar: \"'COPYRIGHT'\" unpacked with wrong size!
  106. fi
  107. # end of 'COPYRIGHT'
  108. fi
  109. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  110.   echo shar: Will not clobber existing file \"'Makefile'\"
  111. else
  112. echo shar: Extracting \"'Makefile'\" \(606 characters\)
  113. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  114. CFLAGS          = -O
  115. X
  116. PROG          = agrep
  117. HDRS          =    agrep.h checkfile.h re.h
  118. OBJS          =    \
  119. X        asearch.o    \
  120. X        asearch1.o    \
  121. X        bitap.o        \
  122. X        checkfile.o    \
  123. X        compat.o    \
  124. X        follow.o    \
  125. X        main.o        \
  126. X        maskgen.o    \
  127. X        parse.o        \
  128. X        preprocess.o    \
  129. X        sgrep.o        \
  130. X        mgrep.o        \
  131. X        utilities.o
  132. X
  133. X$(PROG):    $(OBJS)
  134. X        $(CC) $(CFLAGS) -o $@ $(OBJS)
  135. X
  136. clean:
  137. X        -rm -f $(OBJS) core a.out
  138. X
  139. asearch.o:    agrep.h
  140. asearch1.o:    agrep.h
  141. bitap.o:    agrep.h
  142. checkfile.o:    checkfile.h
  143. follow.o:    re.h
  144. main.o:        agrep.h checkfile.h
  145. maskgen.o:    agrep.h
  146. next.o:        agrep.h
  147. parse.o:    re.h
  148. preprocess.o:    agrep.h
  149. sgrep.o:    agrep.h
  150. abm.o:        agrep.h
  151. utilities.o:    re.h
  152. END_OF_FILE
  153. if test 606 -ne `wc -c <'Makefile'`; then
  154.     echo shar: \"'Makefile'\" unpacked with wrong size!
  155. fi
  156. # end of 'Makefile'
  157. fi
  158. if test -f 'README' -a "${1}" != "-c" ; then 
  159.   echo shar: Will not clobber existing file \"'README'\"
  160. else
  161. echo shar: Extracting \"'README'\" \(3629 characters\)
  162. sed "s/^X//" >'README' <<'END_OF_FILE'
  163. This is version 2.01 of agrep - a new tool for fast 
  164. text searching allowing errors.
  165. agrep is similar to egrep (or grep or fgrep), but it is much more general
  166. X(and usually faster).
  167. The main changes from version 1.1 are 1) incorporating Boyer-Moore
  168. type filtering to speed up search considerably, 2) allowing multi patterns 
  169. via the -f option; this is similar to fgrep, but from our experience 
  170. agrep is much faster, 3) searching for "best match" without having to
  171. specify the number of errors allowed, and 4) ascii is no longer required.
  172. Several more options were added.
  173. X
  174. The three most significant features of agrep that are not supported by
  175. the grep family are 
  176. X1) the ability to search for approximate patterns;
  177. X    for example, "agrep -2 homogenos foo" will find homogeneous as well 
  178. X    as any other word that can be obtained from homogenos with at most 
  179. X    2 substitutions, insertions, or deletions.
  180. X    "agrep -B homogenos foo" will generate a message of the form
  181. X    best match has 2 errors, there are 5 matches, output them? (y/n)
  182. X2) agrep is record oriented rather than just line oriented;  a record
  183. X    is by default a line, but it can be user defined;
  184. X    for example, "agrep -d '^From ' 'pizza' mbox"
  185. X    outputs all mail messages that contain the keyword "pizza".
  186. X    Another example:  "agrep -d '$$' pattern foo" will output all
  187. X    paragraphs (separated by an empty line) that contain pattern.
  188. X3) multiple patterns with AND (or OR) logic queries.   
  189. X    For example, "agrep -d '^From ' 'burger,pizza' mbox" 
  190. X    outputs all mail messages containing at least one of the 
  191. X    two keywords (, stands for OR).
  192. X    "agrep -d '^From ' 'good;pizza' mbox" outputs all mail messages
  193. X    containing both keywords.
  194. X
  195. Putting these options together one can ask queries like
  196. X
  197. agrep -d '$$' -2 '<CACM>;TheAuthor;Curriculum;<198[5-9]>' bib
  198. X
  199. which outputs all paragraphs referencing articles in CACM between 
  200. X1985 and 1989 by TheAuthor dealing with curriculum.  
  201. Two errors are allowed, but they cannot be in either CACM or the year 
  202. X(the <> brackets forbid errors in the pattern between them).  
  203. X
  204. Other features include searching for regular expressions (with or
  205. without errors), unlimited wild cards, limiting the errors to only 
  206. insertions or only substitutions or any combination, 
  207. allowing each deletion, for example, to be counted as, say, 
  208. X2 substitutions or 3 insertions, restricting parts of the query 
  209. to be exact and parts to be approximate, and many more.
  210. X
  211. agrep is available by anonymous ftp from cs.arizona.edu (IP 192.12.69.5)
  212. as agrep/agrep-2.01.tar.Z (or in uncompressed form as agrep/agrep-2.01.tar).
  213. The tar file contains the source code (in C), man pages (agrep.1),
  214. and two additional files, agrep.algorithms and agrep.chronicle,
  215. giving more information.
  216. The agrep directory also includes two postscript files: 
  217. agrep.ps.1 is a technical report from June 1991 
  218. describing the design and implementation of agrep;
  219. agrep.ps.2 is a copy of the paper as appeared in the 1992
  220. Winter USENIX conference.
  221. X
  222. Please mail bug reports (or any other comments) 
  223. to sw@cs.arizona.edu or to udi@cs.arizona.edu.
  224. X
  225. We would appreciate if users notify us (at the address above)
  226. of any extensions, improvements, or interesting uses of this software.
  227. X
  228. January 17, 1992
  229. X
  230. X
  231. BUGS found and fixed:
  232. X1. multiple definitions of some global variables.
  233. X   (though haven't caused real problems)
  234. X2. -G option doesn't work.
  235. X   (compat.c do too much checking. After remove the checking of
  236. X    -c option against -G option, and it works.)
  237. X3. -w option forced the first character in the pattern to match.
  238. X    remove the restriction.
  239. January 23, 1992
  240. END_OF_FILE
  241. if test 3629 -ne `wc -c <'README'`; then
  242.     echo shar: \"'README'\" unpacked with wrong size!
  243. fi
  244. # end of 'README'
  245. fi
  246. if test -f 'agrep.algorithms' -a "${1}" != "-c" ; then 
  247.   echo shar: Will not clobber existing file \"'agrep.algorithms'\"
  248. else
  249. echo shar: Extracting \"'agrep.algorithms'\" \(2654 characters\)
  250. sed "s/^X//" >'agrep.algorithms' <<'END_OF_FILE'
  251. The implementation of agrep includes the following algorithms.
  252. XExcept for exact matching of simple patterns, for which we use 
  253. a simple variation of the Boyer-Moore algorithm, 
  254. all the algorithms (listed below) were designed by Sun Wu and Udi Manber.
  255. X
  256. X1. bitap:  The most general algorithm inside agrep.
  257. X       It supports many extensions such as approximate regular expression 
  258. X       pattern matching, non-uniform costs, simultaneous matching of 
  259. X       multiple patterns, mixed exact/approximate matching, etc.
  260. X       The algorithm is described in agrep.ps.1.
  261. X
  262. X2. mgrep:  A sub-linear expect-time algorithm for matching a set of patterns.
  263. X       It assumes that the set of patterns contains k patterns, and that
  264. X       the shortest pattern is of size m.
  265. X       See agrep.ps.2 for a brief description of the algorithm.
  266. X
  267. X3. amonkey: a Boyer-Moore style algorithm for approximate pattern matching.
  268. X       let b = log_c (2*m), where c is the size of alphabet set.
  269. X       In the preprocessing, a table is built to determine whether
  270. X       a given substring of size b is in the pattern.
  271. X       Suppose we are looking for matches with at most k errors.
  272. X       The search is done in two passes.
  273. X       In the first pass (the filtering pass), the areas in the text
  274. X       that have a possibility to contain the matches are marked.
  275. X       The second pass finds the matches in those marked areas.
  276. X       The search in the first pass is done in the following way.
  277. X       Suppose the end position of the pattern is currently aligned with 
  278. X       position tx in the text.
  279. X       The algorithm scans backward from tx until either (k+1) blocks
  280. X       that do not occur in the pattern have been scanned, or
  281. X       the scan has passed position (tx-m+k).
  282. X       In the former case, pattern is shifted forward to align
  283. X       the beginning position of the pattern with one character after
  284. X       the position in the text where the scan was stopped.
  285. X       In the latter case, we marked tx-m to tx+m as a candidate area.
  286. X
  287. X4. mmonkey: Combining the mgrep algorithm with a partition technique, we
  288. X       have an algorithm with the same time complexity as amonkey.
  289. X       For ASCII text and pattern, this algorithm is faster than amonkey.
  290. X       The principle of the partition technique is as follows.
  291. X       Let A and B be two strings of size m. 
  292. X       If we partition A into (k+1) blocks, then the distance between 
  293. X       A and B is > k if none of the blocks of A occur in B. 
  294. X       This implies that to match A with no more than k errors, 
  295. X       B has to contain a substring that matches exactly one block of A.
  296. X       A brief description can be found in agrep.ps.2.
  297. X
  298. END_OF_FILE
  299. if test 2654 -ne `wc -c <'agrep.algorithms'`; then
  300.     echo shar: \"'agrep.algorithms'\" unpacked with wrong size!
  301. fi
  302. # end of 'agrep.algorithms'
  303. fi
  304. if test -f 'agrep.chronicle' -a "${1}" != "-c" ; then 
  305.   echo shar: Will not clobber existing file \"'agrep.chronicle'\"
  306. else
  307. echo shar: Extracting \"'agrep.chronicle'\" \(2561 characters\)
  308. sed "s/^X//" >'agrep.chronicle' <<'END_OF_FILE'
  309. This chronicle briefly describes the progress of agrep.
  310. X
  311. XFeb/91: The approximate pattern matching algorithm called 'bitap'
  312. X    (bit-parallel approximate pattern matching) is designed.
  313. X    The algorithm is a generalization of Baeza-Yates' "shift-or"
  314. X    algorithm for exact matching.
  315. X
  316. Mar/91: Many extensions of the algorithm 'bitap' are found, especially
  317. X    for approximate regular expression pattern matching.  Preliminary
  318. X    implementation of the algorithm showed a strong promise for 
  319. X    a general-purpose fast approximate pattern-matching tool.
  320. X
  321. Apr/91: Approximate regular expression pattern matching was implemented.
  322. X    The result is even better than expected. 
  323. X    The design of the software tool is pinned down.
  324. X    (For example, record oriented, multi-pattern, AND/OR logic queries.)
  325. X    A partition technique for approximate pattern matching is used.
  326. X    
  327. May/91: The prototype of "agrep" is completed.
  328. X    A lot of debugging/optimization in this month.
  329. X
  330. Jun/91: The first version of agrep is released.
  331. X    agrep 1.0 was announced and made available by anonymous ftp 
  332. X    from cs.arizona.edu.
  333. X
  334. Jul/91: A sub-linear expected-time algorithm, called "amonkey" for 
  335. X    approximate pattern matching (for simple pattern) is designed.
  336. X    The algorithm has the same time complexity as that of
  337. X    Chang&Lawler but is much much faster in practice.
  338. X    The algorithm is based on a variation of Boyer-Moore technique,
  339. X    which we call "block-shifting." 
  340. X    A sub-linear expected-time algorithm, called "mgrep" for 
  341. X    matching a set of patterns is designed based on the "block-shifting" 
  342. X    technique with a hashing technique.
  343. X
  344. Aug/91: "amonkey" is implemented and incorporated into agrep.
  345. X    It is very fast for long patterns like DNA patterns.
  346. X    (But roughly the same for matching English words as the bitap
  347. X    algorithm using the partition technique.)
  348. X    Prototype of "mgrep" is implemented.
  349. X
  350. Sep/91: "mgrep" is incorporated into agrep to support the -f option.
  351. X    An algorithm for approximate pattern matching that combines the 
  352. X    'partition' technique with the sub-linear expected-time algorithm 
  353. X    for multi-patterns is designed.
  354. X    Implementation shows it to be the fastest for ASCII text (and pattern).
  355. X    Boyer-moore technique for exact matching is incorporated.
  356. X
  357. Nov/91: The final paper of "agrep" that is to appear in USENIX
  358. X    conference (Jan 1992)  is finished.
  359. X
  360. Jan/92: Some new options are added, such as find best matches (-B), 
  361. X    and file outputs (-G).
  362. X    The man pages are revised.
  363. X    agrep version 2.0 is released.
  364. X
  365. END_OF_FILE
  366. if test 2561 -ne `wc -c <'agrep.chronicle'`; then
  367.     echo shar: \"'agrep.chronicle'\" unpacked with wrong size!
  368. fi
  369. # end of 'agrep.chronicle'
  370. fi
  371. if test -f 'agrep.h' -a "${1}" != "-c" ; then 
  372.   echo shar: Will not clobber existing file \"'agrep.h'\"
  373. else
  374. echo shar: Extracting \"'agrep.h'\" \(1837 characters\)
  375. sed "s/^X//" >'agrep.h' <<'END_OF_FILE'
  376. X#include <stdio.h>
  377. X#include <math.h>
  378. X#include <ctype.h>
  379. X#include "re.h"
  380. X
  381. extern unsigned char *strcpy(), *strncpy(), *strcat();
  382. extern int strlen();
  383. X#define CHAR    unsigned char
  384. X#define MAXPAT 128
  385. X#define MAXPATT 256
  386. X#define MAXDELIM 8            /* Max size of a delimiter pattern */
  387. X#define SHORTREG 15
  388. X#define MAXREG   30
  389. X#define MAXNAME  256
  390. X#define Max_Pats 12    /* max num of patterns */
  391. X#define Max_Keys 12    /* max num of keywords */
  392. X#define Max_Psize 128  /* max size of a pattern counting all the characters */
  393. X#define Max_Keyword 31 /* the max size of a keyword */
  394. X#define WORD 32        /* the size of a word */
  395. X#define MaxError 8     /* the max number of errors allowed */
  396. X#define MaxRerror 4    /* the max number of erros for regular expression */
  397. X#define MaxDelimit 16   /* the max raw length of a user defined delimiter */
  398. X#define BlockSize  49152
  399. X#define Max_record 49152
  400. X#define SIZE 16384       /* BlockSIze in sgrep */
  401. X#define MAXLINE   1024  /* maxline in sgrep */
  402. X#define Maxline   1024
  403. X#define RBLOCK    8192
  404. X#define RMAXLINE  1024
  405. X#define MaxNext   66000
  406. X#define ON 1
  407. X#define OFF 0
  408. X#define Compl 1
  409. X#define Maxresult 10000
  410. X#define MaxCan 2500
  411. X#define MAXSYM 256 /* ASCII */
  412. X#define WORDB     241    /* -w option */
  413. X#define LPARENT   242    /* ( */
  414. X#define RPARENT   243    /* ) */
  415. X#define LRANGE    244    /* [ */
  416. X#define RRANGE    245    /* ] */
  417. X#define LANGLE    246    /* < */
  418. X#define RANGLE    247    /* > */
  419. X#define NOTSYM    248    /* ^ */
  420. X#define WILDCD    249    /* wildcard */
  421. X#define ORSYM     250   /* | */
  422. X#define ORPAT     251   /* , */
  423. X#define ANDPAT    252   /* ; */
  424. X#define STAR      253   /* closure */
  425. X#define HYPHEN    237   /* - */
  426. X#define NOCARE    238   /* . */
  427. X#define NNLINE    239   /* special symbol for newline in begin of pattern*/
  428. X                       /* matches '\n' and NNLINE */
  429. X
  430. END_OF_FILE
  431. if test 1837 -ne `wc -c <'agrep.h'`; then
  432.     echo shar: \"'agrep.h'\" unpacked with wrong size!
  433. fi
  434. # end of 'agrep.h'
  435. fi
  436. if test -f 'asearch1.c' -a "${1}" != "-c" ; then 
  437.   echo shar: Will not clobber existing file \"'asearch1.c'\"
  438. else
  439. echo shar: Extracting \"'asearch1.c'\" \(5049 characters\)
  440. sed "s/^X//" >'asearch1.c' <<'END_OF_FILE'
  441. X/* Copyright (c) 1991 Sun Wu and Udi Manber.  All Rights Reserved. */
  442. X#include "agrep.h"
  443. extern unsigned Init1, Init[], Mask[], endposition, D_endpos;
  444. extern unsigned NO_ERR_MASK;
  445. extern int TRUNCATE, DELIMITER, AND, I, S, DD, INVERSE, FILENAMEONLY ;
  446. extern char CurrentFileName[];
  447. extern int num_of_matched;
  448. X
  449. X
  450. asearch1(old_D_pat, Text, D)
  451. char old_D_pat[]; int Text; register unsigned D;
  452. X{
  453. X  register unsigned end, i, r1, r2, r3, r4, r5, CMask, D_Mask, Init0, k, endpos; 
  454. X  register unsigned r_NO_ERR;
  455. X  unsigned A[MaxError*2+1], B[MaxError*2+1];
  456. X  int D_length, ResidueSize, lasti, num_read,  FIRSTROUND, j=0;
  457. X  char buffer[BlockSize+Max_record+1];
  458. X   
  459. X  if(I == 0) Init1 = 037777777777;
  460. X  if(DD > D) DD = D+1;
  461. X  if(I  > D) I  = D+1;
  462. X  if(S  > D) S  = D+1;
  463. X  D_length = strlen(old_D_pat);
  464. X  buffer[Max_record-1] = '\n';
  465. X   
  466. X  lasti = Max_record;
  467. X  r_NO_ERR = NO_ERR_MASK;
  468. X
  469. X  D_Mask = D_endpos;
  470. X  for(i=1 ; i<D_length; i++) D_Mask = (D_Mask << 1) | D_Mask;
  471. X  D_Mask = ~D_Mask;
  472. X  endpos = D_endpos;
  473. X  r3 = D+1; r4 = D*2;  /* to make sure in register */
  474. X  for(k=0; k < D;   k++) A[k] = B[k] = 0;
  475. X  for(k=D; k <= r4; k++) A[k] = B[k] = Init[0];
  476. X   
  477. X  while ((num_read = fill_buf(Text, buffer + Max_record, Max_record)) > 0)
  478. X  {
  479. X    i=Max_record; end = Max_record + num_read;
  480. X    if(FIRSTROUND) { i = Max_record -1 ;
  481. X            if(DELIMITER) {
  482. X                for(k=0; k<D_length; k++) {
  483. X                    if(old_D_pat[k] != buffer[Max_record+k])                         break;
  484. X                }
  485. X                if(k>=D_length) j--;
  486. X            }
  487. X                     FIRSTROUND = 0; }
  488. X    if(num_read < BlockSize) {
  489. X                      strncpy(buffer+Max_record+num_read, old_D_pat, D_length);
  490. X                      end = end + D_length;
  491. X                      buffer[end] = '\0';
  492. X    }
  493. X    while (i < end)
  494. X    {
  495. X        CMask = Mask[buffer[i++]];
  496. X              r1 = Init1 & B[D];
  497. X              A[D] = ((B[D] >> 1) & CMask )  | r1;
  498. X              for(k = r3; k <= r4; k++)  /* r3 = D+1, r4 = 2*D */
  499. X              { 
  500. X                  r5 = B[k];
  501. X                  r1 = Init1 & r5;
  502. X                  A[k] = ((r5 >> 1) & CMask) | B[k-I] |                                                (((A[k-DD] | B[k-S]) >>1) & r_NO_ERR) | r1 ; 
  503. X              }
  504. X        if(A[D] & endpos) {  
  505. X           j++;
  506. X           if(((AND == 1) && ((A[D*2] & endposition) == endposition)) ||                           ((AND == 0) && (A[D*2] & endposition)) ^ INVERSE )
  507. X                   { 
  508. X                     if(FILENAMEONLY) {
  509. X            num_of_matched++;
  510. X                        printf("%s\n", CurrentFileName);
  511. X                        return;       } 
  512. X                     if(lasti < Max_record + num_read)
  513. X                        output(buffer, lasti, i-D_length-1, j); 
  514. X                   }
  515. X           lasti = i - D_length;
  516. X           TRUNCATE = OFF;
  517. X           for(k = D; k <= r4 ; k++) A[k] = B[k] = Init[0];
  518. X           r1 = Init1 & B[D];
  519. X           A[D] = (((B[D] >> 1) & CMask )  | r1) & D_Mask;
  520. X           for(k = r3; k <= r4; k++)  /* r3 = D+1, r4 = 2*D */
  521. X              { 
  522. X                  r5 = B[k];
  523. X                  r1 = Init1 & r5;
  524. X                  A[k] = ((r5 >> 1) & CMask) | B[k-I] |                                                (((A[k-DD] | B[k-S]) >>1) & r_NO_ERR) | r1 ; 
  525. X              }
  526. X        }  /* end if (A[D]&endpos) */
  527. X        CMask = Mask[buffer[i++]];
  528. X              r1 = A[D] & Init1;
  529. X              B[D] = ((A[D] >> 1) & CMask) | r1;
  530. X              for(k = r3; k <= r4; k++)
  531. X              { 
  532. X                  r1 = A[k] & Init1;
  533. X                  B[k] = ((A[k] >> 1) & CMask) | A[k-I] |                                                (((B[k-DD] | A[k-S]) >>1)&r_NO_ERR) | r1 ; 
  534. X              }
  535. X        if(B[D] & endpos)  {  
  536. X             j++;
  537. X           if(((AND == 1) && ((B[r4] & endposition) == endposition)) ||                           ((AND == 0) && (B[r4] & endposition)) ^ INVERSE )
  538. X                   { if(FILENAMEONLY) {
  539. X                        num_of_matched++;
  540. X                        printf("%s\n", CurrentFileName);
  541. X                        return;       }
  542. X                     if(lasti < Max_record + num_read)
  543. X                        output(buffer, lasti, i-D_length-1, j); 
  544. X                   } 
  545. X           lasti = i-D_length; 
  546. X           TRUNCATE = OFF;
  547. X           for(k=D; k <= r4; k++) A[k] = B[k] = Init[0];
  548. X           r1 = Init1 & A[D];
  549. X           B[D] = (((A[D] >> 1) & CMask )  | r1) & D_Mask;
  550. X           for(k = r3; k <= r4; k++)  /* r3 = D+1, r4 = 2*D */
  551. X              { 
  552. X                  r5 = A[k];
  553. X                  r1 = Init1 & r5;
  554. X                  B[k] = ((r5 >> 1) & CMask) | A[k-I] |                                                (((B[k-DD] | A[k-S]) >>1) & r_NO_ERR) | r1 ; 
  555. X              }
  556. X        }  /* end if (B[D]&endpos) */
  557. X    }
  558. X    ResidueSize = Max_record + num_read - lasti;
  559. X    if(ResidueSize > Max_record) {
  560. X            ResidueSize = Max_record;
  561. X            TRUNCATE = ON;   
  562. X    }
  563. X    strncpy(buffer+Max_record-ResidueSize, buffer+lasti, ResidueSize);
  564. X    lasti = Max_record - ResidueSize;
  565. X    if(lasti < 0) lasti = 1;
  566. X    if(num_read < BlockSize) lasti = Max_record;
  567. X  }
  568. X  return;
  569. X}
  570. X
  571. END_OF_FILE
  572. if test 5049 -ne `wc -c <'asearch1.c'`; then
  573.     echo shar: \"'asearch1.c'\" unpacked with wrong size!
  574. fi
  575. # end of 'asearch1.c'
  576. fi
  577. if test -f 'bitap.c' -a "${1}" != "-c" ; then 
  578.   echo shar: Will not clobber existing file \"'bitap.c'\"
  579. else
  580. echo shar: Extracting \"'bitap.c'\" \(5407 characters\)
  581. sed "s/^X//" >'bitap.c' <<'END_OF_FILE'
  582. X/* Copyright (c) 1991 Sun Wu and Udi Manber.  All Rights Reserved. */
  583. X/* if the pattern is not simple fixed pattern, then after preprocessing */
  584. X/* and generating the masks, the program goes here. four cases:  1.     */ 
  585. X/* the pattern is simple regular expression and no error, then do the   */
  586. X/* matching here.  2. the pattern is simple regular expression and      */
  587. X/* unit cost errors are allowed: then go to asearch().                  */
  588. X/* 3. the pattern is simple regular expression, and the edit cost is    */
  589. X/* not uniform, then go to asearch1().                                  */
  590. X/* if the pattern is regular expression then go to re() if M < 14,      */
  591. X/* else go to re1()                                                     */
  592. X/* input parameters: old_D_pat: delimiter pattern.                      */
  593. X/* fd, input file descriptor, M: size of pattern, D: # of errors.       */
  594. X
  595. X#include "agrep.h"
  596. X
  597. extern unsigned Init1, D_endpos, endposition, Init[], Mask[], Bit[];
  598. extern int DELIMITER, FILENAMEONLY, D_length, I, AND, REGEX, JUMP, INVERSE; 
  599. extern char D_pattern[];
  600. extern int TRUNCATE, DD, S;
  601. extern char Progname[], CurrentFileName[];
  602. extern int num_of_matched;
  603. X
  604. X/* bitap dispatches job */
  605. X
  606. bitap(old_D_pat, Pattern, fd, M, D)
  607. char old_D_pat[], *Pattern;  int fd, M, D;  
  608. X{
  609. char c;  
  610. register unsigned r1, r2, r3, CMask, i;
  611. register unsigned end, endpos, r_Init1;
  612. register unsigned D_Mask;
  613. int  ResidueSize , FIRSTROUND, lasti, print_end, j, num_read;
  614. int  k;
  615. char buffer[Max_record+Max_record+BlockSize];
  616. X  D_length = strlen(old_D_pat);
  617. X  for(i=0; i<D_length; i++) if(old_D_pat[i] == '^' || old_D_pat[i] == '$')
  618. X                               old_D_pat[i] = '\n';
  619. X  if (REGEX) { 
  620. X      if (D > 4) {
  621. X          fprintf(stderr, "%s: the maximum number of erorrs allowed for full regular expression is 4\n", Progname);
  622. X          exit(2);
  623. X      }
  624. X      if (M <= SHORTREG) { re(fd, M, D);   /* SUN: need to find a even point */ 
  625. X                     return; }
  626. X      else { re1(fd, M, D); 
  627. X             return; }
  628. X  }   
  629. X  if (D > 0 && JUMP == ON) 
  630. X     { asearch1(old_D_pat, fd, D); return; }
  631. X  if (D > 0) 
  632. X     { asearch(old_D_pat, fd, D); return; }
  633. X  if(I == 0) Init1 = 037777777777;
  634. X
  635. X  j=0;
  636. X  lasti = Max_record;
  637. X  buffer[Max_record-1] = '\n';
  638. X  r_Init1 = Init1;
  639. X  r1 = r2 = r3 = Init[0];
  640. X  endpos = D_endpos;
  641. X  
  642. X  buffer[Max_record-1] = '\n';
  643. X  D_Mask = D_endpos;
  644. X  for(i=1 ; i<D_length; i++) D_Mask = (D_Mask << 1) | D_Mask;
  645. X  D_Mask = ~D_Mask;
  646. X  FIRSTROUND = ON;
  647. X
  648. X  while ((num_read = fill_buf(fd, buffer + Max_record, Max_record)) > 0)
  649. X  {
  650. X    i=Max_record; end = Max_record + num_read; 
  651. X    if(FIRSTROUND) {  i = Max_record - 1 ;
  652. X
  653. X            if(DELIMITER) {
  654. X                for(k=0; k<D_length; k++) {
  655. X                    if(old_D_pat[k] != buffer[Max_record+k])                         break;
  656. X                }
  657. X                if(k>=D_length) j--;
  658. X            }
  659. X
  660. X                      FIRSTROUND = OFF;  }
  661. X    if(num_read < BlockSize) {
  662. X                      strncpy(buffer+Max_record+num_read, old_D_pat, D_length);
  663. X                      end = end + D_length;
  664. X                      buffer[end] = '\0';
  665. X    }
  666. X    while (i < end)
  667. X    {
  668. X        c = buffer[i++];
  669. X        CMask = Mask[c];
  670. X              r1 = r_Init1 & r3;
  671. X              r2 = (( r3 >> 1 ) & CMask) | r1;
  672. X        if ( r2 & endpos ) {
  673. X           j++;
  674. X           if(((AND == 1) && ((r2 & endposition) == endposition)) ||                           ((AND == 0) && (r2 & endposition)) ^ INVERSE )
  675. X               { 
  676. X                 if(FILENAMEONLY) {
  677. X                    num_of_matched++;
  678. X                    printf("%s\n", CurrentFileName);
  679. X                    return; }
  680. X                 print_end = i - D_length - 1;
  681. X                 if(!(lasti >= Max_record+num_read - 1))
  682. X                    output(buffer, lasti, print_end, j); 
  683. X               }
  684. X           lasti = i - D_length; 
  685. X           TRUNCATE = OFF;
  686. X           r2 = r3 = r1 = Init[0];
  687. X           r1 = r_Init1 & r3;
  688. X           r2 = ((( r2 >> 1) & CMask) | r1 ) & D_Mask;
  689. X        }
  690. X        c = buffer[i++];
  691. X        CMask = Mask[c];
  692. X              r1 = r_Init1 & r2;
  693. X              r3 = (( r2 >> 1 ) & CMask) | r1; 
  694. X        if ( r3 & endpos ) {
  695. X           j++;
  696. X           if(((AND == 1) && ((r3 & endposition) == endposition)) ||                           ((AND == 0) && (r3 & endposition)) ^ INVERSE )
  697. X               { 
  698. X                 if(FILENAMEONLY) {
  699. X                    num_of_matched++;
  700. X                    printf("%s\n", CurrentFileName);
  701. X                    return; }
  702. X                 print_end = i - D_length - 1;
  703. X                 if(!(lasti >= Max_record+num_read - 1))
  704. X                    output(buffer, lasti, print_end, j);
  705. X               }
  706. X           lasti = i - D_length ;
  707. X           TRUNCATE = OFF;
  708. X           r2 = r3 = r1 = Init[0]; 
  709. X           r1 = r_Init1 & r2;
  710. X           r3 = ((( r2 >> 1) & CMask) | r1 ) & D_Mask;
  711. X       }   
  712. X    }
  713. X    ResidueSize = num_read + Max_record - lasti;
  714. X    if(ResidueSize > Max_record) {
  715. X            ResidueSize = Max_record;
  716. X            TRUNCATE = ON;   
  717. X    }
  718. X    strncpy(buffer+Max_record-ResidueSize, buffer+lasti, ResidueSize);
  719. X    lasti = Max_record - ResidueSize;
  720. X    if(lasti < 0) {
  721. X       lasti = 1;
  722. X    } 
  723. X  }
  724. X  return;
  725. X}
  726. X
  727. fill_buf(fd, buf, record_size)
  728. int fd, record_size; unsigned char *buf;
  729. X{
  730. int num_read=1;
  731. int total_read=0;
  732. X    while(total_read < record_size && num_read > 0) {
  733. X        num_read = read(fd, buf+total_read, 4096);
  734. X        total_read = total_read + num_read;
  735. X    }
  736. X    return(total_read);
  737. X}
  738. X
  739. END_OF_FILE
  740. if test 5407 -ne `wc -c <'bitap.c'`; then
  741.     echo shar: \"'bitap.c'\" unpacked with wrong size!
  742. fi
  743. # end of 'bitap.c'
  744. fi
  745. if test -f 'checkfile.c' -a "${1}" != "-c" ; then 
  746.   echo shar: Will not clobber existing file \"'checkfile.c'\"
  747. else
  748. echo shar: Extracting \"'checkfile.c'\" \(2149 characters\)
  749. sed "s/^X//" >'checkfile.c' <<'END_OF_FILE'
  750. X/*
  751. X *  checkfile.c
  752. X *    takes a file descriptor and checks to see if a file is a regular
  753. X *    ascii file
  754. X *
  755. X */
  756. X
  757. X#include <stdio.h>
  758. X#include <ctype.h>
  759. X#include <fcntl.h>
  760. X#include <sys/types.h>
  761. X#include <sys/stat.h>
  762. X#include <errno.h>
  763. X
  764. X#include "checkfile.h"
  765. X
  766. X#define MAXLINE 512
  767. X
  768. extern char Progname[];
  769. extern int errno;
  770. X
  771. unsigned char ibuf[MAXLINE];
  772. X
  773. X/**************************************************************************
  774. X*
  775. X*    check_file
  776. X*       input:  filename or path (null-terminated character string)
  777. X*       returns: int (0 if file is a regular file, non-0 if not)
  778. X*
  779. X*    uses stat(2) to see if a file is a regular file.
  780. X*
  781. X***************************************************************************/
  782. X
  783. int check_file(fname)
  784. char *fname;
  785. X
  786. X{
  787. struct stat buf;
  788. int ftype;
  789. X
  790. X
  791. X  if (stat(fname, &buf) != 0) {
  792. X    if (errno == ENOENT)
  793. X      return NOSUCHFILE;
  794. X    else
  795. X      return STATFAILED;  
  796. X    } else {
  797. X/*
  798. X      if (S_ISREG(buf.st_mode)) {
  799. X        if ((ftype = samplefile(fname)) == ISASCIIFILE) {
  800. X          return ISASCIIFILE;
  801. X        } else if (ftype == ISBINARYFILE) {
  802. X          return ISBINARYFILE;
  803. X        } else if (ftype == OPENFAILED) {
  804. X          return OPENFAILED;
  805. X        }
  806. X      }
  807. X      if (S_ISDIR(buf.st_mode)) {
  808. X        return ISDIRECTORY;
  809. X      }
  810. X      if (S_ISBLK(buf.st_mode)) {
  811. X        return ISBLOCKFILE;
  812. X      }
  813. X      if (S_ISSOCK(buf.st_mode)) {
  814. X        return ISSOCKET;
  815. X      }
  816. X*/
  817. X    }
  818. X}
  819. X
  820. X/***************************************************************************
  821. X*
  822. X*  samplefile
  823. X*    reads in the first part of a file, and checks to see that it is
  824. X*    all ascii.
  825. X*
  826. X***************************************************************************/
  827. X/*
  828. int samplefile(fname)
  829. char *fname;
  830. X{
  831. char *p;
  832. int numread;
  833. int fd;
  834. X
  835. X  if ((fd = open(fname, O_RDONLY)) == -1) {
  836. X    fprintf(stderr, "open failed on filename %s\n", fname);
  837. X    return OPENFAILED;
  838. X  }
  839. X  if (numread = read(fd, ibuf, MAXLINE)) {
  840. X   close(fd);
  841. X   p = ibuf;
  842. X    while (isascii(*p++) && --numread);
  843. X    if (!numread) {
  844. X      return(ISASCIIFILE);
  845. X    } else {
  846. X      return(ISBINARYFILE);
  847. X    }
  848. X  } else {
  849. X    close(fd);
  850. X    return(ISASCIIFILE);
  851. X  }
  852. X}
  853. X*/
  854. END_OF_FILE
  855. if test 2149 -ne `wc -c <'checkfile.c'`; then
  856.     echo shar: \"'checkfile.c'\" unpacked with wrong size!
  857. fi
  858. # end of 'checkfile.c'
  859. fi
  860. if test -f 'checkfile.h' -a "${1}" != "-c" ; then 
  861.   echo shar: Will not clobber existing file \"'checkfile.h'\"
  862. else
  863. echo shar: Extracting \"'checkfile.h'\" \(174 characters\)
  864. sed "s/^X//" >'checkfile.h' <<'END_OF_FILE'
  865. X#define NOSUCHFILE -3
  866. X#define OPENFAILED -2
  867. X#define STATFAILED -1
  868. X#define ISASCIIFILE 0
  869. X#define ISDIRECTORY 1
  870. X#define ISBLOCKFILE 2
  871. X#define ISSOCKET 3
  872. X#define ISBINARYFILE 4
  873. END_OF_FILE
  874. if test 174 -ne `wc -c <'checkfile.h'`; then
  875.     echo shar: \"'checkfile.h'\" unpacked with wrong size!
  876. fi
  877. # end of 'checkfile.h'
  878. fi
  879. if test -f 'compat.c' -a "${1}" != "-c" ; then 
  880.   echo shar: Will not clobber existing file \"'compat.c'\"
  881. else
  882. echo shar: Extracting \"'compat.c'\" \(1301 characters\)
  883. sed "s/^X//" >'compat.c' <<'END_OF_FILE'
  884. X/* test the conflicts between options */
  885. X#include <stdio.h>
  886. X
  887. extern int FILENAMEONLY, APPROX, PAT_FILE, COUNT, INVERSE, BESTMATCH;
  888. extern FILEOUT;
  889. extern REGEX;
  890. extern DELIMITER;
  891. extern WHOLELINE;
  892. extern LINENUM;
  893. extern I, S, DD;
  894. extern JUMP;
  895. extern char Progname[32];
  896. X
  897. compat()
  898. X{
  899. int i, j, k;
  900. X    if(BESTMATCH)  if(COUNT || FILENAMEONLY || APPROX || PAT_FILE) {
  901. X        BESTMATCH = 0;
  902. X        fprintf(stderr, "WARNING!!! -B option ignored when -c, -l, -f, or -# is on\n", Progname);
  903. X    }
  904. X    if(PAT_FILE)   {
  905. X        if(APPROX)  {
  906. X            fprintf(stderr, "WARNING!!!  approximate matching is not supported with -f option\n");
  907. X        }
  908. X/*
  909. X        if(INVERSE) {
  910. X            fprintf(stderr, "%s: -f and -v are not compatible\n", Progname);
  911. X            exit(2);
  912. X        }
  913. X*/
  914. X        if(LINENUM) {
  915. X            fprintf(stderr, "%s: -f and -n are not compatible\n", Progname);
  916. X            exit(2);
  917. X        }
  918. X        if(DELIMITER) {
  919. X            fprintf(stderr, "%s: -f and -d are not compatible\n", Progname);
  920. X            exit(2);
  921. X        }
  922. X    }
  923. X    if(JUMP) {
  924. X        if(REGEX) {
  925. X            fprintf(stderr, "WARNING!!! -D#, -I#, or -S# option is ignored for regular expression pattern\n");
  926. X            JUMP = 0;
  927. X        }
  928. X        if(I == 0 || S == 0 || DD == 0) {
  929. X            fprintf(stderr, "%s: the error cost cannot be 0\n", Progname);
  930. X            exit(2);
  931. X        }
  932. X    }
  933. X    if(DELIMITER) {
  934. X        if(WHOLELINE) {
  935. X            fprintf(stderr, "%s: -d and -x is not compatible\n", Progname);
  936. X            exit(2);
  937. X        }
  938. X    }
  939. X
  940. X}
  941. END_OF_FILE
  942. if test 1301 -ne `wc -c <'compat.c'`; then
  943.     echo shar: \"'compat.c'\" unpacked with wrong size!
  944. fi
  945. # end of 'compat.c'
  946. fi
  947. if test -f 'contribution.list' -a "${1}" != "-c" ; then 
  948.   echo shar: Will not clobber existing file \"'contribution.list'\"
  949. else
  950. echo shar: Extracting \"'contribution.list'\" \(318 characters\)
  951. sed "s/^X//" >'contribution.list' <<'END_OF_FILE'
  952. List of people who have contributed to agrep:
  953. X
  954. Chunghwa H. Rao
  955. Gene Myers
  956. Ricardo Baeza-Yates
  957. Cliff Hathaway 
  958. Ric Anderson 
  959. Su-Ing Tsuei
  960. Raphael Finkel
  961. Andrew Hume
  962. David W. Sanderson
  963. William I. Chang
  964. Jack Kirman
  965. Dave Lutz
  966. Tony Plate
  967. Ken Lalonde
  968. Mark Christopher
  969. Dieter Becker
  970. Ian Young
  971. James M. Winget
  972. John F. Stoffel
  973. END_OF_FILE
  974. if test 318 -ne `wc -c <'contribution.list'`; then
  975.     echo shar: \"'contribution.list'\" unpacked with wrong size!
  976. fi
  977. # end of 'contribution.list'
  978. fi
  979. if test -f 'follow.c' -a "${1}" != "-c" ; then 
  980.   echo shar: Will not clobber existing file \"'follow.c'\"
  981. else
  982. echo shar: Extracting \"'follow.c'\" \(3224 characters\)
  983. sed "s/^X//" >'follow.c' <<'END_OF_FILE'
  984. X/* the functions in this file take a syntax tree for a regular
  985. X   expression and produce a DFA using the McNaughton-Yamada
  986. X   construction.                        */
  987. X
  988. X#include <stdio.h>
  989. X#include "re.h"
  990. X
  991. extern char *strncpy(), *strcat(), *strcpy();
  992. extern int  strlen();
  993. X
  994. X#define TRUE    1
  995. X
  996. extern char *malloc();
  997. extern Pset pset_union(); 
  998. extern int pos_cnt;
  999. extern Re_node parse();
  1000. X
  1001. Re_lit_array lpos; 
  1002. X
  1003. X
  1004. X/*  extend_re() extends the RE by adding a ".*(" at the front and a "("
  1005. X    at the back.                               */
  1006. X
  1007. char *extend_re(s)
  1008. char *s;
  1009. X{
  1010. X    char *s1;
  1011. X
  1012. X    s1 = malloc((unsigned) strlen(s)+4+1);
  1013. X    return strcat(strcat(strcpy(s1, ".*("), s), ")");
  1014. X}
  1015. X
  1016. X/* mk_followpos() takes a syntax tree for a regular expression and
  1017. X   traverses it once, computing the followpos function at each node
  1018. X   and returns a pointer to an array whose ith element is a pointer
  1019. X   to a list of position nodes, representing the positions in
  1020. X   followpos(i).                            */
  1021. X
  1022. void mk_followpos_1(e, fpos)
  1023. Re_node e;
  1024. Pset_array fpos;
  1025. X{
  1026. X    Pset pos;
  1027. X    int i;
  1028. X
  1029. X    switch (Op(e)) {
  1030. X    case EOS: break;
  1031. X    case OPSTAR:
  1032. X        pos = Lastpos(e);
  1033. X        while (pos != NULL) {
  1034. X        i = pos->posnum;
  1035. X        (*fpos)[i] = pset_union(Firstpos(e), (*fpos)[i]);
  1036. X        pos = pos->nextpos;
  1037. X        }
  1038. X        mk_followpos_1(Child(e), fpos);
  1039. X        break;
  1040. X    case OPCAT:
  1041. X        pos = Lastpos(Lchild(e));
  1042. X        while (pos != NULL) {
  1043. X        i = pos->posnum;
  1044. X        (*fpos)[i] = pset_union(Firstpos(Rchild(e)), (*fpos)[i]);
  1045. X        pos = pos->nextpos;
  1046. X        }
  1047. X        mk_followpos_1(Lchild(e), fpos);
  1048. X        mk_followpos_1(Rchild(e), fpos);
  1049. X        break;
  1050. X    case OPOPT:
  1051. X        mk_followpos_1(Child(e), fpos);
  1052. X        break;
  1053. X    case OPALT:
  1054. X        mk_followpos_1(Lchild(e), fpos);
  1055. X        mk_followpos_1(Rchild(e), fpos);
  1056. X        break;
  1057. X    case LITERAL:
  1058. X        break;
  1059. X    default: printf("mk_followpos: unknown node type %d\n", Op(e));
  1060. X    }
  1061. X    return;
  1062. X}
  1063. X
  1064. Pset_array mk_followpos(tree, npos)
  1065. Re_node tree;
  1066. int npos;
  1067. X{
  1068. X    int i;
  1069. X    Pset_array fpos;
  1070. X
  1071. X    if (tree == NULL || npos < 0) return NULL;
  1072. X    fpos = (Pset_array) malloc((unsigned) (npos+1)*sizeof(Pset));
  1073. X    if (fpos == NULL) return NULL;
  1074. X    for (i = 0; i <= npos; i++) (*fpos)[i] = NULL;
  1075. X    mk_followpos_1(tree, fpos);
  1076. X    return fpos;
  1077. X}
  1078. X
  1079. X/* mk_poslist() sets a static array whose i_th element is a pointer to
  1080. X   the RE-literal at position i.  It returns 1 if everything is OK,  0
  1081. X   otherwise.                                */
  1082. X
  1083. X/* init performs initialization actions; it returns -1 in case of error,
  1084. X   0 if everything goes OK.                        */
  1085. X
  1086. int init(s, table)
  1087. char *s; int table[32][32];
  1088. X{
  1089. X    Pset_array fpos;
  1090. X    Re_node e;
  1091. X    Pset l;
  1092. X    int i, j;
  1093. X
  1094. X    if ((e = parse(extend_re(s))) == NULL) return -1;
  1095. X    if ((fpos = mk_followpos(e, pos_cnt)) == NULL) return -1;
  1096. X    for (i = 0; i <= pos_cnt; i += 1) {
  1097. X#ifdef Debug
  1098. X    printf("followpos[%d] = ", i);
  1099. X#endif
  1100. X        l = (*fpos)[i];
  1101. X        j = 0;
  1102. X        for ( ; l != NULL; l = l->nextpos)  {
  1103. X#ifdef Debug
  1104. X            printf("%d ", l->posnum);
  1105. X#endif
  1106. X            table[i][j] = l->posnum;
  1107. X            j++;
  1108. X        } 
  1109. X#ifdef Debug
  1110. X        printf("\n");
  1111. X#endif
  1112. X    }
  1113. X#ifdef Debug
  1114. X    for (i=0; i <= pos_cnt; i += 1)  {
  1115. X       j = 0;
  1116. X       while (table[i][j] != 0) {
  1117. X          printf(" %d ", table[i][j]);
  1118. X          j++;
  1119. X      }
  1120. X      printf("\n");
  1121. X   }
  1122. X#endif
  1123. X    return (pos_cnt);
  1124. X}
  1125. X
  1126. END_OF_FILE
  1127. if test 3224 -ne `wc -c <'follow.c'`; then
  1128.     echo shar: \"'follow.c'\" unpacked with wrong size!
  1129. fi
  1130. # end of 'follow.c'
  1131. fi
  1132. if test -f 'maskgen.c' -a "${1}" != "-c" ; then 
  1133.   echo shar: Will not clobber existing file \"'maskgen.c'\"
  1134. else
  1135. echo shar: Extracting \"'maskgen.c'\" \(6459 characters\)
  1136. sed "s/^X//" >'maskgen.c' <<'END_OF_FILE'
  1137. X/* Copyright (c) 1991 Sun Wu and Udi Manber.  All Rights Reserved. */
  1138. X#include "agrep.h"
  1139. extern unsigned D_endpos, endposition, Init1, wildmask;
  1140. extern Mask[], Bit[], Init[], NO_ERR_MASK;
  1141. extern int AND, SIMPLEPATTERN, REGEX, NOUPPER, D_length;
  1142. extern unsigned char Progname[];
  1143. X       
  1144. maskgen(Pattern, D)
  1145. unsigned char *Pattern; int D;
  1146. X{
  1147. struct term { int flag; unsigned char class[WORD];
  1148. X            } position[WORD+10];
  1149. unsigned char c;
  1150. X
  1151. int i, j, k, l, M, OR=0, EVEN = 0, base, No_error;
  1152. X
  1153. X
  1154. for(i=0; i<WORD; i++) position[i].class[0] = '\0';
  1155. for(i=0; i<WORD; i++) position[i].flag = 0;
  1156. wildmask = NO_ERR_MASK = endposition = 0;
  1157. No_error = 0;
  1158. M = strlen(Pattern);
  1159. if(NOUPPER) {
  1160. X              for(i=0; i<M; i++) if(isalpha(Pattern[i])) 
  1161. X                     if (isupper(Pattern[i])) Pattern[i] = tolower(Pattern[i]);
  1162. X            }
  1163. X#ifdef DEBUG
  1164. X    for(i=0; i<M; i++) printf(" %d", Pattern[i]);
  1165. X    printf("\n");
  1166. X#endif
  1167. for (i=0, j=1; i< M; i++)
  1168. X{
  1169. X  switch (Pattern[i])
  1170. X  {
  1171. X    case WILDCD : if(REGEX) {
  1172. X                     position[j].class[0] = '.';
  1173. X                     position[j].class[1] = '.';
  1174. X                     position[j++].class[2] = '\0'; 
  1175. X                     break;
  1176. X                  }
  1177. X                  wildmask = wildmask | Bit[j-1]; break;
  1178. X    case STAR   : break; 
  1179. X    case ORSYM  : break; 
  1180. X    case LPARENT: break;
  1181. X    case RPARENT: break;
  1182. X    case LANGLE : No_error = ON; EVEN++;
  1183. X                  break;
  1184. X    case RANGLE : No_error = OFF; EVEN--;
  1185. X                  if(EVEN < 0) {
  1186. X                     fprintf(stderr, "%s: illegal pattern, unmatched '<', '>'\n", Progname);
  1187. X                     exit(2);
  1188. X                  }
  1189. X                  break;
  1190. X    case LRANGE : if(No_error == ON) NO_ERR_MASK = NO_ERR_MASK | Bit[j]; 
  1191. X                  i=i+1; 
  1192. X                  if (Pattern[i] == NOTSYM) { position[j].flag = Compl; i++; }
  1193. X                  k=0;
  1194. X                  while (Pattern[i] != RRANGE && i < M)
  1195. X                  { 
  1196. X                    if(Pattern[i] == HYPHEN) 
  1197. X                       { position[j].class[k-1] = Pattern[i+1]; i=i+2; }
  1198. X                    else { 
  1199. X                     position[j].class[k] = position[j].class[k+1] = Pattern[i];
  1200. X                     k = k+2; i++;
  1201. X                    }
  1202. X                  }
  1203. X                  if(i == M) {
  1204. X                     fprintf(stderr, "%s: illegal pattern, unmatched '[', ']'\n",Progname);
  1205. X                     exit(2);
  1206. X                  }
  1207. X                  position[j].class[k] = '\0';
  1208. X                  j++; break;
  1209. X    case RRANGE : fprintf(stderr, "%s: illegal pattern, unmatched '[', ']'\n", Progname); 
  1210. X                  exit(2);
  1211. X                  break;     
  1212. X    case ORPAT  : if(REGEX == ON || AND == ON) {
  1213. X                     fprintf(stderr, "illegal pattern \n");
  1214. X                     exit(2);
  1215. X                  }
  1216. X                  OR = ON;
  1217. X                  position[j].flag = 2; position[j].class[0] = '\0';
  1218. X                  endposition = endposition | Bit[j++]; break;
  1219. X    case ANDPAT : position[j].flag = 2; position[j].class[0] = '\0'; 
  1220. X                  if(j > D_length) AND = ON;
  1221. X                  if(OR || (REGEX == ON && j>D_length)) {
  1222. X                     fprintf(stderr, "illegal pattern \n");
  1223. X                     exit(2);
  1224. X                  }
  1225. X                  endposition = endposition | Bit[j++]; break;
  1226. X/*
  1227. X    case ' '    : if (Pattern[i-1] == ORPAT || Pattern[i-1] == ANDPAT) break;
  1228. X                  if(No_error == ON) NO_ERR_MASK = NO_ERR_MASK | Bit[j];
  1229. X                  position[j].flag = 0;
  1230. X                  position[j].class[0] = position[j].class[1] = Pattern[i];
  1231. X                  position[j++].class[2] = '\0';  break;
  1232. X*/
  1233. X    case '\n'   : NO_ERR_MASK = NO_ERR_MASK | Bit[j];
  1234. X                  position[j].class[0] = position[j].class[1] = '\n';
  1235. X                  position[j++].class[2] = '\0'; 
  1236. X                  break;
  1237. X    case WORDB  : NO_ERR_MASK = NO_ERR_MASK | Bit[j];
  1238. X                  position[j].class[0] = 1;
  1239. X                  position[j].class[1] = 47;
  1240. X                  position[j].class[2] = 58;
  1241. X                  position[j].class[3] = 64;
  1242. X                  position[j].class[4] = 91;
  1243. X                  position[j].class[5] = 96;
  1244. X                  position[j].class[6] = 123;
  1245. X                  position[j].class[7] = 127;
  1246. X                  position[j++].class[8] = '\0';
  1247. X                  break;    
  1248. X    case NNLINE : NO_ERR_MASK |= Bit[j];
  1249. X                  position[j].class[0] = position[j].class[1] = '\n';
  1250. X                  position[j].class[2] = position[j].class[3] = NNLINE;
  1251. X                  position[j++].class[4] = '\0';
  1252. X                  break;
  1253. X    default : if(No_error == ON) NO_ERR_MASK = NO_ERR_MASK | Bit[j];
  1254. X                  position[j].flag = 0;
  1255. X                  position[j].class[0] = position[j].class[1] = Pattern[i];
  1256. X                  position[j++].class[2] = '\0'; 
  1257. X  }
  1258. X  if(j > WORD) {
  1259. X     fprintf(stderr, "%s: pattern too long\n", Progname);
  1260. X     exit(2);
  1261. X  }
  1262. X}
  1263. X  if (EVEN != 0) {
  1264. X     fprintf(stderr, "%s: illegal pattern, unmatched '<', '>'\n", Progname);
  1265. X     exit(2);
  1266. X  }
  1267. M = j - 1;
  1268. base = WORD - M;
  1269. wildmask = (wildmask >> base);
  1270. endposition = (endposition >> base);
  1271. NO_ERR_MASK = (NO_ERR_MASK >> 1) & (~Bit[1]);
  1272. NO_ERR_MASK = ~NO_ERR_MASK >> (base-1);
  1273. X  for (i=1; i<= WORD - M ; i++) Init[0] = Init[0] | Bit[i];
  1274. X  Init[0] = Init[0] | endposition;
  1275. X             /* not necessary for INit[i], i>0, */
  1276. X             /* but at every begining of the matching process append one
  1277. X                no-match character to initialize the error vectors */
  1278. X  endposition = ( endposition << 1 ) + 1;
  1279. X  Init1 = (Init[0] | wildmask | endposition) ;
  1280. X  D_endpos = ( endposition >> ( M - D_length ) ) << ( M - D_length);
  1281. X  endposition = endposition ^ D_endpos;
  1282. X#ifdef DEBUG
  1283. X    printf("endposition: %o\n", endposition);
  1284. X    printf("no_err_mask: %o\n", NO_ERR_MASK);
  1285. X#endif
  1286. X  for(c=0, i=0; i < MAXSYM; c++, i++)
  1287. X  {
  1288. X     for (k=1, l=0; k<=M ; k++, l=0)  {
  1289. X         while (position[k].class[l] != '\0') {
  1290. X               if (position[k].class[l] == NOCARE && (c != '\n' || REGEX) ) 
  1291. X                  {  Mask[c] = Mask[c] | Bit[base + k]; break; }
  1292. X               if (c >= position[k].class[l] && c <= position[k].class[l+1])
  1293. X                  {  Mask[c] = Mask[c] | Bit[base + k]; break; }
  1294. X               l = l + 2;  }
  1295. X         if (position[k].flag == Compl) Mask[c] = Mask[c] ^ Bit[base+k];
  1296. X     }
  1297. X  }
  1298. X  if(NOUPPER) for(c='A'; c<='Z'; c=c+1) if (isupper(c)) 
  1299. X                  Mask[c] = Mask[tolower(c)]; 
  1300. X  return(M);
  1301. X}
  1302. X
  1303. END_OF_FILE
  1304. if test 6459 -ne `wc -c <'maskgen.c'`; then
  1305.     echo shar: \"'maskgen.c'\" unpacked with wrong size!
  1306. fi
  1307. # end of 'maskgen.c'
  1308. fi
  1309. if test -f 'preprocess.c' -a "${1}" != "-c" ; then 
  1310.   echo shar: Will not clobber existing file \"'preprocess.c'\"
  1311. else
  1312. echo shar: Extracting \"'preprocess.c'\" \(7657 characters\)
  1313. sed "s/^X//" >'preprocess.c' <<'END_OF_FILE'
  1314. X/* Copyright (c) 1991 Sun Wu and Udi Manber.  All Rights Reserved. */
  1315. X/* substitute metachar with special symbol                               */
  1316. X/* if regularr expression, then set flag REGEX                           */
  1317. X/* if REGEX and MULTIPAT then report error message,                      */
  1318. X/* -w only for single word pattern. If WORDBOUND & MULTIWORD error       */
  1319. X/* process start of line, endof line symbol,                             */
  1320. X/* process -w WORDBOUND option, append special symbol at begin&end of    */
  1321. X/* process -d option before this routine                                 */
  1322. X/* the delimiter pattern is in D_pattern (need to end with '; ')          */
  1323. X/* if '-t' (suggestion: how about -B) the pattern is passed to sgrep     */
  1324. X/* and doesn't go here                                                   */
  1325. X/* in that case, -d is ignored? or not necessary                         */
  1326. X/* upon return, Pattern contains the pattern to be processed by maskgen  */
  1327. X/* D_pattern contains transformed D_pattern                              */
  1328. X   
  1329. X#include "agrep.h"
  1330. X  
  1331. extern int SIMPLEPATTERN, WHOLELINE, REGEX, RE_ERR, DELIMITER, TAIL, WORDBOUND;
  1332. extern int HEAD;
  1333. extern CHAR Progname[];
  1334. extern int D_length;
  1335. extern int table[WORD][WORD];
  1336. X  
  1337. preprocess(D_pattern, Pattern)   /* need two parameters  */
  1338. CHAR *D_pattern, *Pattern;
  1339. X{
  1340. X  CHAR temp[Maxline], *r_pat, *old_pat;  /* r_pat for r.e. */
  1341. X  CHAR old_D_pat[MaxDelimit];
  1342. X  int i, j=0, rp=0, m, t=0, partitions, num_pos, ANDON = 0;
  1343. X  int d_end ;  
  1344. X  int IN_RANGE=0, EVEN=0, OR_AND=0;
  1345. X  old_pat = Pattern; /* to remember the starting position */
  1346. X  m = strlen(Pattern);
  1347. X  for(i=0; i< m; i++) {
  1348. X      if(Pattern[i] == '\\') i++;
  1349. X      else if(Pattern[i] == '|' || Pattern[i] == '*' ) REGEX = ON;   
  1350. X  }
  1351. X  r_pat = (CHAR *) malloc(strlen(Pattern)+2*strlen(D_pattern));
  1352. X  strcpy(temp, D_pattern);
  1353. X  d_end = t = strlen(temp);  /* size of D_pattern, including '; ' */
  1354. X  if (WHOLELINE) { temp[t++] = LANGLE; 
  1355. X                   temp[t++] = NNLINE; 
  1356. X                   temp[t++] = RANGLE;
  1357. X                   temp[t] = '\0';
  1358. X                   strcat(temp, Pattern);
  1359. X                   m = strlen(temp);
  1360. X                   temp[m++] = LANGLE; 
  1361. X                   temp[m++] = '\n'; 
  1362. X                   temp[m++] = RANGLE; 
  1363. X                   temp[m] = '\0';  }
  1364. X  else {
  1365. X     if (WORDBOUND) { temp[t++] = LANGLE; 
  1366. X                      temp[t++] = WORDB; 
  1367. X                      temp[t++] = RANGLE;
  1368. X                      temp[t] = '\0'; }
  1369. X     strcat(temp, Pattern);
  1370. X     m = strlen(temp);
  1371. X     if (WORDBOUND) { temp[m++] = LANGLE; 
  1372. X                      temp[m++] = WORDB; 
  1373. X                      temp[m++] = RANGLE; }
  1374. X     temp[m] = '\0';
  1375. X  }
  1376. X        /* now temp contains augmented pattern , m it's size */
  1377. X
  1378. X  D_length = 0;
  1379. X  for (i=0, j=0; i< d_end-2; i++) {
  1380. X      switch(temp[i]) 
  1381. X      {
  1382. X         case '\\' : i++; 
  1383. X                     Pattern[j++] = temp[i];
  1384. X                     old_D_pat[D_length++] = temp[i];
  1385. X                     break;
  1386. X         case '<'  : Pattern[j++] = LANGLE;
  1387. X                     break;
  1388. X         case '>'  : Pattern[j++] = RANGLE;
  1389. X                     break;
  1390. X         case '^'  : Pattern[j++] = '\n';
  1391. X                     old_D_pat[D_length++] = temp[i];
  1392. X                     break;
  1393. X         case '$'  : Pattern[j++] = '\n';
  1394. X                     old_D_pat[D_length++] = temp[i];
  1395. X                     break;
  1396. X         default  :  Pattern[j++] = temp[i];
  1397. X                     old_D_pat[D_length++] = temp[i];
  1398. X                     break;
  1399. X     }
  1400. X  }
  1401. X  if(D_length > MAXDELIM) {
  1402. X     fprintf(stderr, "%s: delimiter pattern too long\n", Progname);
  1403. X     exit(2);
  1404. X  }
  1405. X  Pattern[j++] = ANDPAT;
  1406. X  old_D_pat[D_length] = '\0';
  1407. X  strcpy(D_pattern, old_D_pat);
  1408. X  D_length++;
  1409. X/*
  1410. X  Pattern[j++] = ' ';
  1411. X*/
  1412. X  Pattern[j] = '\0';
  1413. X  rp = 0; 
  1414. X  if(REGEX) {
  1415. X      r_pat[rp++] = '.';    /* if REGEX: always append '.' in front */
  1416. X      r_pat[rp++] = '(';
  1417. X      Pattern[j++] = NOCARE;
  1418. X      HEAD = ON;
  1419. X  }
  1420. X  for (i=d_end; i < m ; i++)
  1421. X  {
  1422. X       switch(temp[i]) 
  1423. X       {
  1424. X           case '\\': i++;  Pattern[j++] = temp[i]; 
  1425. X                      r_pat[rp++] = 'o';   /* the symbol doesn't matter */
  1426. X                      break;
  1427. X           case '#':  if(REGEX) {
  1428. X                         Pattern[j++] = NOCARE;
  1429. X                         r_pat[rp++] = '.';
  1430. X                         r_pat[rp++] = '*';
  1431. X                         break; }
  1432. X                      Pattern[j++] = WILDCD;
  1433. X                      break; 
  1434. X           case '(':  Pattern[j++] = LPARENT; 
  1435. X                      r_pat[rp++] = '(';     
  1436. X                      break;
  1437. X           case ')':  Pattern[j++] = RPARENT; 
  1438. X                      r_pat[rp++] = ')'; 
  1439. X                      break;
  1440. X           case '[':  Pattern[j++] = LRANGE;  
  1441. X                      r_pat[rp++] = '[';
  1442. X                      IN_RANGE = ON;
  1443. X                      break;
  1444. X           case ']':  Pattern[j++] = RRANGE;  
  1445. X                      r_pat[rp++] = ']'; 
  1446. X              IN_RANGE = OFF;
  1447. X                      break;
  1448. X           case '<':  Pattern[j++] = LANGLE;  
  1449. X                      break;
  1450. X           case '>':  Pattern[j++] = RANGLE;  
  1451. X                      break;
  1452. X           case '^':  if (temp[i-1] == '[') Pattern[j++] = NOTSYM;
  1453. X                      else Pattern[j++] = '\n';
  1454. X                      r_pat[rp++] = '^';
  1455. X                      break;
  1456. X           case '$':  Pattern[j++] = '\n'; 
  1457. X                      r_pat[rp++] = '$';
  1458. X                      break;
  1459. X           case '.':  Pattern[j++] = NOCARE;
  1460. X                      r_pat[rp++] = '.';
  1461. X                      break;
  1462. X           case '*':  Pattern[j++] = STAR; 
  1463. X                      r_pat[rp++] = '*';
  1464. X                      break;
  1465. X           case '|':  Pattern[j++] = ORSYM; 
  1466. X                      r_pat[rp++] = '|';
  1467. X                      break;
  1468. X           case ',':  Pattern[j++] = ORPAT;  
  1469. X                      RE_ERR = ON; 
  1470. X                      break;
  1471. X           case ';':  if(ANDON) RE_ERR = ON; 
  1472. X                      Pattern[j++] = ANDPAT;
  1473. X                      ANDON = ON;
  1474. X                      break;
  1475. X           case '-':  if(IN_RANGE) {
  1476. X                          Pattern[j++] = HYPHEN; 
  1477. X                          r_pat[rp++] = '-';
  1478. X                      }
  1479. X                      else { 
  1480. X                          Pattern[j++] = temp[i];
  1481. X                          r_pat[rp++] = temp[i];
  1482. X                      }  
  1483. X                      break;
  1484. X           case NNLINE :
  1485. X                      Pattern[j++] = temp[i];
  1486. X                      r_pat[rp++] = 'N';
  1487. X                      break;
  1488. X           default:   Pattern[j++] = temp[i]; 
  1489. X                      r_pat[rp++] = temp[i];
  1490. X                      break;
  1491. X      }
  1492. X  }
  1493. X  if(REGEX) {           /* append ').' at end of regular expression */
  1494. X      r_pat[rp++] = ')';
  1495. X      r_pat[rp++] = '.';
  1496. X      Pattern[j++] = NOCARE;
  1497. X      TAIL = ON;
  1498. X  }
  1499. X  Pattern[j] = '\0'; 
  1500. X  m = j;
  1501. X  r_pat[rp] = '\0'; 
  1502. X  if(REGEX)
  1503. X  {  
  1504. X     if(DELIMITER || WORDBOUND)  {
  1505. X          fprintf(stderr, "%s: -d or -w option is not supported for this pattern\n", Progname);
  1506. X          exit(2);
  1507. X     }
  1508. X     if(RE_ERR) {
  1509. X        fprintf(stderr, "%s: illegal regular expression\n", Progname);
  1510. X        exit(2);
  1511. X     }
  1512. X     while(*Pattern != NOCARE && m-- > 0) Pattern++;  /* poit to . */
  1513. X     num_pos = init(r_pat, table);
  1514. X     if(num_pos <= 0) {
  1515. X         fprintf(stderr, "%s: illegal regular expression\n", Progname);
  1516. X         exit(2);
  1517. X     }
  1518. X     if(num_pos > 30) {
  1519. X        fprintf(stderr, "%s: regular expression too long\n", Progname);
  1520. X        exit(2);
  1521. X     }
  1522. X  strcpy(old_pat, Pattern); /* do real change to the Pattern to be returned */
  1523. X  return;
  1524. X  } /* if regex */
  1525. X
  1526. X  return;
  1527. X}
  1528. X
  1529. END_OF_FILE
  1530. if test 7657 -ne `wc -c <'preprocess.c'`; then
  1531.     echo shar: \"'preprocess.c'\" unpacked with wrong size!
  1532. fi
  1533. # end of 'preprocess.c'
  1534. fi
  1535. if test -f 're.h' -a "${1}" != "-c" ; then 
  1536.   echo shar: Will not clobber existing file \"'re.h'\"
  1537. else
  1538. echo shar: Extracting \"'re.h'\" \(3433 characters\)
  1539. sed "s/^X//" >'re.h' <<'END_OF_FILE'
  1540. X/*************************************************************
  1541. X *                                 *
  1542. X *     Macros defining special characters.             *
  1543. X *                                 *
  1544. X *************************************************************/
  1545. X
  1546. X#define NUL        '\0'
  1547. X#define ASCII_MIN   '\001'
  1548. X#define ASCII_MAX   '\177'
  1549. X
  1550. X/*************************************************************
  1551. X *                                 *
  1552. X *     Macros defining lexical categories.             *
  1553. X *                                 *
  1554. X *************************************************************/
  1555. X
  1556. X#define C_LIT    0   /* individual character literal */
  1557. X#define C_SET    1   /* character set literal        */
  1558. X
  1559. X#define EOS        0    /* end-of-string */
  1560. X#define LITERAL        1
  1561. X#define OPSTAR        2
  1562. X#define OPALT        3
  1563. X#define OPOPT        4
  1564. X#define OPCAT        5
  1565. X#define LPAREN        6
  1566. X#define RPAREN        7
  1567. X
  1568. X/*************************************************************
  1569. X *                                 *
  1570. X *     Macros for manipulating syntax tree nodes.         *
  1571. X *                                 *
  1572. X *************************************************************/
  1573. X
  1574. X#define lit_type(x)    (x->l_type)
  1575. X#define lit_pos(x)    (x->pos)
  1576. X#define lit_char(x)    ((x->val).c)
  1577. X#define lit_cset(x)    ((x->val).cset)
  1578. X
  1579. X#define tok_type(x)    (x->type)
  1580. X#define tok_val(x)    (x->val)
  1581. X#define tok_op(x)       (x->val->op)
  1582. X#define tok_lit(x)    ((x->val->refs).lit)
  1583. X
  1584. X#define Op(x)        (x->op)
  1585. X#define Lit(x)        ((x->refs).lit)
  1586. X#define Child(x)    ((x->refs).child)
  1587. X#define Lchild(x)    ((x->refs).children.l_child)
  1588. X#define Rchild(x)    ((x->refs).children.r_child)
  1589. X#define Nullable(x)    (x->nullable)
  1590. X#define Firstpos(x)    (x->firstposn)
  1591. X#define Lastpos(x)    (x->lastposn)
  1592. X
  1593. X/*************************************************************
  1594. X *                                 *
  1595. X *  Macros for manipulating DFA states and sets of states.   *
  1596. X *                                 *
  1597. X *************************************************************/
  1598. X
  1599. X#define Positions(x)    (x->posns)
  1600. X#define Final_St(x)    (x->final)
  1601. X#define Goto(x, c)    ((x->trans)[c])
  1602. X#define Next_State(x)    ((x)->next_state)
  1603. X
  1604. X/*************************************************************/
  1605. X
  1606. X#define new_node(x)    malloc(sizeof(*x))
  1607. X
  1608. typedef struct {    /* character range literals */
  1609. X        char low_bd, hi_bd;
  1610. X    } *Ch_Range;
  1611. X
  1612. typedef struct ch_set {        /* character set literals */
  1613. X        Ch_Range elt;    /* rep. as list of ranges */
  1614. X        struct ch_set *rest;
  1615. X    } *Ch_Set;
  1616. X
  1617. typedef struct {    /* regular expression literal */
  1618. X        int pos;         /* position in syntax tree */
  1619. X        short l_type;    /* type of literal */
  1620. X        union {
  1621. X        char c;     /* for character literals */
  1622. X        Ch_Set cset; /* for character sets */
  1623. X        } val;
  1624. X    } *Re_Lit, *(*Re_lit_array)[];
  1625. X
  1626. typedef struct pnode {
  1627. X        int posnum;
  1628. X        struct pnode *nextpos;
  1629. X    } *Pset, *(*Pset_array)[];
  1630. X
  1631. typedef struct rnode {    /* regular expression node */
  1632. X        short op;     /* operator at that node */
  1633. X        union {
  1634. X        Re_Lit lit;        /* child is a leaf node */
  1635. X        struct rnode *child;    /* child of unary op */
  1636. X        struct {
  1637. X            struct rnode *l_child; 
  1638. X            struct rnode *r_child;
  1639. X        } children;        /* children of binary op */
  1640. X        } refs;
  1641. X        short nullable;
  1642. X        Pset firstposn, lastposn;
  1643. X    } *Re_node;
  1644. X
  1645. typedef struct {            /* token node */
  1646. X        short type;
  1647. X        Re_node val;
  1648. X    } *Tok_node;
  1649. X
  1650. X
  1651. typedef struct snode {
  1652. X        Re_node val;
  1653. X        int size;
  1654. X        struct snode *next;
  1655. X    } *Stack;
  1656. X
  1657. typedef struct dfa_st {
  1658. X        Pset posns;
  1659. X        int final;        /* 1 if the state is a final state, 0 o/w */
  1660. X        struct dfa_st *trans[128];
  1661. X    } *Dfa_state;
  1662. X
  1663. typedef struct dfa_stset {
  1664. X        Dfa_state st;
  1665. X        struct dfa_stset *next_state;
  1666. X    } *Dfa_state_set;
  1667. X
  1668. X
  1669. END_OF_FILE
  1670. if test 3433 -ne `wc -c <'re.h'`; then
  1671.     echo shar: \"'re.h'\" unpacked with wrong size!
  1672. fi
  1673. # end of 're.h'
  1674. fi
  1675. if test -f 'utilities.c' -a "${1}" != "-c" ; then 
  1676.   echo shar: Will not clobber existing file \"'utilities.c'\"
  1677. else
  1678. echo shar: Extracting \"'utilities.c'\" \(2977 characters\)
  1679. sed "s/^X//" >'utilities.c' <<'END_OF_FILE'
  1680. X/* this file contains various utility functions for accessing
  1681. X   and manipulating regular expression syntax trees.    */
  1682. X
  1683. X#include <stdio.h>
  1684. X#include "re.h"
  1685. X
  1686. X/************************************************************************/
  1687. X/*                                                                      */
  1688. X/*  the following routines implement an abstract data type "stack".    */
  1689. X/*                                                                      */
  1690. X/************************************************************************/
  1691. X
  1692. Stack Push(s, v)
  1693. Stack *s;
  1694. Re_node v;
  1695. X{
  1696. X    Stack node;
  1697. X
  1698. X    node = (Stack) new_node(node);
  1699. X    if (s == NULL || node == NULL) return NULL;        /* can't allocate */
  1700. X    node->next = *s;
  1701. X    node->val = v;
  1702. X    if (*s == NULL) node->size = 1;
  1703. X    else node->size = (*s)->size + 1;
  1704. X    *s = node;
  1705. X    return *s;
  1706. X}
  1707. X
  1708. Re_node Pop(s)
  1709. Stack *s;
  1710. X{
  1711. X    Re_node node;
  1712. X    Stack temp;
  1713. X
  1714. X    if (s == NULL || *s == NULL) return NULL;
  1715. X    else {
  1716. X    temp = *s;
  1717. X    node = (*s)->val;
  1718. X    *s = (*s)->next;
  1719. X    free(temp);
  1720. X    return node;
  1721. X    }
  1722. X}
  1723. X
  1724. Re_node Top(s)
  1725. Stack s;
  1726. X{
  1727. X    if (s == NULL) return NULL;
  1728. X    else return s->val;
  1729. X}
  1730. X
  1731. int Size(s)
  1732. Stack s;
  1733. X{
  1734. X    if (s == NULL) return 0;
  1735. X    else return s->size;
  1736. X}
  1737. X
  1738. X/************************************************************************/
  1739. X/*                                                                      */
  1740. X/*    the following routines manipulate sets of positions.        */
  1741. X/*                                                                      */
  1742. X/************************************************************************/
  1743. X
  1744. int occurs_in(n, p)
  1745. int n;
  1746. Pset p;
  1747. X{
  1748. X    while (p != NULL)
  1749. X    if (n == p->posnum) return 1;
  1750. X    else p = p->nextpos;
  1751. X    return 0;
  1752. X}
  1753. X
  1754. X/* pset_union() takes two position-sets and returns their union.    */
  1755. X
  1756. Pset pset_union(s1, s2)
  1757. Pset s1, s2;
  1758. X{
  1759. X    Pset hd, curr, new;
  1760. X    int occ;
  1761. X
  1762. X    hd = NULL; curr = NULL;
  1763. X    while (s1 != NULL) {
  1764. X    if (!occurs_in(s1->posnum, s2)) {
  1765. X        new = (Pset) new_node(new);
  1766. X        if (new == NULL) return NULL;
  1767. X        new->posnum = s1->posnum;
  1768. X        if (hd == NULL) hd = new;
  1769. X        else curr->nextpos = new;
  1770. X    }
  1771. X    curr = new;
  1772. X    s1 = s1->nextpos;
  1773. X    }
  1774. X    if (hd == NULL) hd = s2;
  1775. X    else curr->nextpos = s2;
  1776. X    return hd;
  1777. X}
  1778. X
  1779. X/* create_pos() creates a position node with the position value given,
  1780. X   then returns a pointer to this node.                    */
  1781. X
  1782. Pset create_pos(n)
  1783. int n;
  1784. X{
  1785. X    Pset x;
  1786. X
  1787. X    x = (Pset) new_node(x);
  1788. X    if (x == NULL) return NULL;
  1789. X    x->posnum = n;
  1790. X    x->nextpos = NULL;
  1791. X    return x;
  1792. X}
  1793. X
  1794. X/* eq_pset() takes two position sets and checks to see if they are
  1795. X   equal.  It returns 1 if the sets are equal, 0 if they are not.    */
  1796. X
  1797. subset_pset(s1, s2)
  1798. Pset s1, s2;
  1799. X{
  1800. X    int subs = 1;
  1801. X
  1802. X    while (s1 != NULL && subs != 0) {
  1803. X    subs = 0;
  1804. X    while (s2 != NULL && subs != 1)
  1805. X        if (s1->posnum == s2->posnum) subs = 1;
  1806. X        else s2 = s2->nextpos;
  1807. X    s1 = s1->nextpos;
  1808. X    }
  1809. X    return subs;
  1810. X}    
  1811. X
  1812. int eq_pset(s1, s2)
  1813. Pset s1, s2;
  1814. X{
  1815. X    return subset_pset(s1, s2) && subset_pset(s2, s1);
  1816. X}
  1817. X
  1818. END_OF_FILE
  1819. if test 2977 -ne `wc -c <'utilities.c'`; then
  1820.     echo shar: \"'utilities.c'\" unpacked with wrong size!
  1821. fi
  1822. # end of 'utilities.c'
  1823. fi
  1824. echo shar: End of archive 1 \(of 3\).
  1825. cp /dev/null ark1isdone
  1826. MISSING=""
  1827. for I in 1 2 3 ; do
  1828.     if test ! -f ark${I}isdone ; then
  1829.     MISSING="${MISSING} ${I}"
  1830.     fi
  1831. done
  1832. if test "${MISSING}" = "" ; then
  1833.     echo You have unpacked all 3 archives.
  1834.     rm -f ark[1-9]isdone
  1835. else
  1836.     echo You still need to unpack the following archives:
  1837.     echo "        " ${MISSING}
  1838. fi
  1839. ##  End of shell archive.
  1840. exit 0
  1841.