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