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