First version of grepper: grep with error correction.
[idzebra-moved-to-github.git] / dfa / agrep.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: agrep.c,v $
7  * Revision 1.3  1994-09-27 16:31:18  adam
8  * First version of grepper: grep with error correction.
9  *
10  * Revision 1.2  1994/09/26  16:30:56  adam
11  * Minor changes. imalloc uses xmalloc now.
12  *
13  * Revision 1.1  1994/09/26  10:16:52  adam
14  * First version of dfa module in alex. This version uses yacc to parse
15  * regular expressions. This should be hand-made instead.
16  *
17  */
18 #include <stdio.h>
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdarg.h>
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28
29
30 #include <util.h>
31 #include <dfa.h>
32 #include "imalloc.h"
33
34 #ifndef O_BINARY
35 #define O_BINARY 0
36 #endif
37
38 static char *prog;
39
40 void error (const char *format, ...)
41 {
42     va_list argptr;
43     va_start (argptr, format);
44     fprintf (stderr, "%s error: ", prog);
45     (void) vfprintf (stderr, format, argptr);
46     putc ('\n', stderr);
47     exit (1);
48 }
49
50 #ifdef YYDEBUG
51 #ifdef YACC
52 extern int yydebug;
53 #else
54 extern int alexdebug;
55 #endif
56 #endif
57
58 static int show_lines = 0;
59
60 int agrep_options (argc, argv)
61 int argc;
62 char **argv;
63 {
64     while (--argc > 0)
65         if (**++argv == '-')
66             while (*++*argv)
67             {
68                 switch (**argv)
69                 {
70                 case 'V':
71                     fprintf (stderr, "%s: %s %s\n", prog, __DATE__, __TIME__);
72                     continue;
73                 case 'v':
74                     dfa_verbose = 1;
75                     continue;
76                 case 'n':
77                     show_lines = 1;
78                     continue;
79 #ifdef YYDEBUG
80                 case 't':
81 #ifdef YACC
82                     yydebug = 1;
83 #else
84                     alexdebug = 1;
85 #endif
86                     continue;
87 #endif
88                 case 'd':
89                     switch (*++*argv)
90                     {
91                     case 's':
92                         debug_dfa_tran = 1;
93                         break;
94                     case 't':
95                         debug_dfa_trav = 1;
96                         break;
97                     case 'f':
98                         debug_dfa_followpos = 1;
99                         break;
100                     default:
101                         --*argv;
102                         debug_dfa_tran = 1;
103                         debug_dfa_followpos = 1;
104                         debug_dfa_trav = 1;
105                     }
106                     continue;
107                 default:
108                     fprintf (stderr, "%s: unknown option `-%s'\n", prog, *argv);
109                     return 1;
110                 }
111                 break;
112             }
113     return 0;
114 }
115
116 #define INF_BUF_SIZE  32768U
117 static char *inf_buf;
118 static char *inf_ptr, *inf_flsh;
119 static int inf_eof, line_no;
120
121 static int inf_flush (fd)
122 int fd;
123 {
124     char *p;
125     unsigned b, r;
126
127     r = (unsigned) (inf_buf+INF_BUF_SIZE - inf_ptr);  /* no of `wrap' bytes */
128     if (r)
129         memcpy (inf_buf, inf_ptr, r);
130     inf_ptr = p = inf_buf + r;
131     b = INF_BUF_SIZE - r;
132     do
133         if ((r = read (fd, p, b)) == (unsigned) -1)
134             return -1;
135         else if (r)
136             p +=  r;
137         else
138         {
139             *p++ = '\n';
140             inf_eof = 1;
141             break;
142         }
143     while ((b -= r) > 0);
144     while (p != inf_buf && *--p != '\n')
145         ;
146     while (p != inf_buf && *--p != '\n')
147         ;
148     inf_flsh = p+1;
149     return 0;
150 }
151
152 static char *prline (p)
153 char *p;
154 {
155     char *p0;
156
157     --p;
158     while (p != inf_buf && p[-1] != '\n')
159         --p;
160     p0 = p;
161     while (*p++ != '\n')
162         ;
163     p[-1] = '\0';
164     if (show_lines)
165         printf ("%5d:\t%s\n", line_no, p0);
166     else
167         puts (p0);
168     p[-1] = '\n';
169     return p;
170 }
171
172 static int go (fd, dfaar)
173 int fd;
174 DFA_state **dfaar;
175 {
176     DFA_state *s = dfaar[0];
177     DFA_tran *t;
178     char *p;
179     int i;
180     unsigned char c;
181
182     while (1)
183     {
184         for (c = *inf_ptr++, t=s->trans, i=s->tran_no; --i >= 0; t++)
185             if (c >= t->ch[0] && c <= t->ch[1])
186             {
187                 p = inf_ptr;
188                 do
189                 {
190                     if ((s = dfaar[t->to])->rule_no)
191                     {
192                         inf_ptr = prline (inf_ptr);
193                         c = '\n';
194                         break;
195                     }
196                     for (t=s->trans, i=s->tran_no; --i >= 0; t++)
197                         if ((unsigned) *p >= t->ch[0] 
198                            && (unsigned) *p <= t->ch[1])
199                             break;
200                     p++;
201                 } while (i >= 0);
202                 s = dfaar[0];
203                 break;
204             }
205         if (c == '\n')
206         {
207             ++line_no;
208             if (inf_ptr == inf_flsh)
209             {
210                 if (inf_eof)
211                     break;
212                 ++line_no;
213                 if (inf_flush (fd))
214                 {
215                     fprintf (stderr, "%s: read error\n", prog);
216                     return -1;
217                 }
218             }
219         }
220     }
221     return 0;
222 }
223
224 int agrep (dfas, fd)
225 DFA_states *dfas;
226 int fd;
227 {
228     inf_buf = imalloc (sizeof(char)*INF_BUF_SIZE);
229     inf_eof = 0;
230     inf_ptr = inf_buf+INF_BUF_SIZE;
231     inf_flush (fd);
232     line_no = 1;
233
234     go (fd, dfas->sortarray);
235
236     ifree (inf_buf);
237     return 0;
238 }
239
240
241 int main (argc, argv)
242 int argc;
243 char **argv;
244 {
245     char *pattern = NULL;
246     char outbuf[BUFSIZ];
247     int fd, i, no = 0;
248     DFA *dfa = init_dfa();
249     DFA_states *dfas;
250
251     prog = *argv;
252 #ifdef YYDEBUG
253 #ifdef YACC
254     yydebug = 0;
255 #else
256     alexdebug = 0;
257 #endif
258 #endif
259     setbuf (stdout, outbuf);
260     i = agrep_options (argc, argv);
261     if (i)
262         return i;
263     while (--argc > 0)
264         if (**++argv != '-' && **argv)
265             if (!pattern)
266             {
267                 pattern = *argv;
268                 i = parse_dfa (dfa, &pattern, dfa_thompson_chars);
269                 if (i || *pattern)
270                 {
271                     fprintf (stderr, "%s: illegal pattern\n", prog);
272                     return 1;
273                 }
274                 dfa->root = dfa->top;
275                 dfas = mk_dfas (dfa, 200);
276                 rm_dfa (&dfa);
277             }
278             else
279             {
280                 ++no;
281                 fd = open (*argv, O_RDONLY | O_BINARY);
282                 if (fd == -1)
283                 {
284                     fprintf (stderr, "%s: couldn't open `%s'\n", prog, *argv);
285                     return 1;
286                 }
287                 i = agrep (dfas, fd);
288                 close (fd);
289                 if (i)
290                     return i;
291             }
292     if (!no)
293     {
294         fprintf (stderr, "%s: no files specified\n", prog);
295         return 2;
296     }
297     fflush(stdout);
298     return 0;
299 }