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