9409baa9797b739d4ae6c6a3dda2aad5fb0b8ddd
[idzebra-moved-to-github.git] / dfa / agrep.c
1 /* $Id: agrep.c,v 1.14 2005-01-15 19:38:18 adam Exp $
2    Copyright (C) 1995-2005
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33
34 #ifdef WIN32
35
36 #include <io.h>
37
38 #else
39 #include <unistd.h>
40 #endif
41
42 #include <zebrautl.h>
43 #include <dfa.h>
44 #include "imalloc.h"
45
46 #ifndef O_BINARY
47 #define O_BINARY 0
48 #endif
49
50 static char *prog;
51
52 void error (const char *format, ...)
53 {
54     va_list argptr;
55     va_start (argptr, format);
56     fprintf (stderr, "%s error: ", prog);
57     (void) vfprintf (stderr, format, argptr);
58     putc ('\n', stderr);
59     exit (1);
60 }
61
62 static int show_lines = 0;
63
64 int agrep_options (argc, argv)
65 int argc;
66 char **argv;
67 {
68     while (--argc > 0)
69         if (**++argv == '-')
70             while (*++*argv)
71             {
72                 switch (**argv)
73                 {
74                 case 'V':
75                     fprintf (stderr, "%s: %s %s\n", prog, __DATE__, __TIME__);
76                     continue;
77                 case 'v':
78                     dfa_verbose = 1;
79                     continue;
80                 case 'n':
81                     show_lines = 1;
82                     continue;
83                 case 'd':
84                     switch (*++*argv)
85                     {
86                     case 's':
87                         debug_dfa_tran = 1;
88                         break;
89                     case 't':
90                         debug_dfa_trav = 1;
91                         break;
92                     case 'f':
93                         debug_dfa_followpos = 1;
94                         break;
95                     default:
96                         --*argv;
97                         debug_dfa_tran = 1;
98                         debug_dfa_followpos = 1;
99                         debug_dfa_trav = 1;
100                     }
101                     continue;
102                 default:
103                     fprintf (stderr, "%s: unknown option `-%s'\n", prog, *argv);
104                     return 1;
105                 }
106                 break;
107             }
108     return 0;
109 }
110
111 #define INF_BUF_SIZE  32768U
112 static char *inf_buf;
113 static char *inf_ptr, *inf_flsh;
114 static int inf_eof, line_no;
115
116 static int inf_flush (fd)
117 int fd;
118 {
119     char *p;
120     unsigned b, r;
121
122     r = (unsigned) (inf_buf+INF_BUF_SIZE - inf_ptr);  /* no of `wrap' bytes */
123     if (r)
124         memcpy (inf_buf, inf_ptr, r);
125     inf_ptr = p = inf_buf + r;
126     b = INF_BUF_SIZE - r;
127     do
128         if ((r = read (fd, p, b)) == (unsigned) -1)
129             return -1;
130         else if (r)
131             p +=  r;
132         else
133         {
134             *p++ = '\n';
135             inf_eof = 1;
136             break;
137         }
138     while ((b -= r) > 0);
139     while (p != inf_buf && *--p != '\n')
140         ;
141     while (p != inf_buf && *--p != '\n')
142         ;
143     inf_flsh = p+1;
144     return 0;
145 }
146
147 static char *prline (p)
148 char *p;
149 {
150     char *p0;
151
152     --p;
153     while (p != inf_buf && p[-1] != '\n')
154         --p;
155     p0 = p;
156     while (*p++ != '\n')
157         ;
158     p[-1] = '\0';
159     if (show_lines)
160         printf ("%5d:\t%s\n", line_no, p0);
161     else
162         puts (p0);
163     p[-1] = '\n';
164     return p;
165 }
166
167 static int go (fd, dfaar)
168 int fd;
169 struct DFA_state **dfaar;
170 {
171     struct DFA_state *s = dfaar[0];
172     struct DFA_tran *t;
173     char *p;
174     int i;
175     unsigned char c;
176     int start_line = 1;
177
178     while (1)
179     {
180         for (c = *inf_ptr++, t=s->trans, i=s->tran_no; --i >= 0; t++)
181             if (c >= t->ch[0] && c <= t->ch[1])
182             {
183                 p = inf_ptr;
184                 do
185                 {
186                     if ((s = dfaar[t->to])->rule_no &&
187                         (start_line || s->rule_nno))
188                     {
189                         inf_ptr = prline (inf_ptr);
190                         c = '\n';
191                         break;
192                     }
193                     for (t=s->trans, i=s->tran_no; --i >= 0; t++)
194                         if ((unsigned) *p >= t->ch[0] 
195                            && (unsigned) *p <= t->ch[1])
196                             break;
197                     p++;
198                 } while (i >= 0);
199                 s = dfaar[0];
200                 break;
201             }
202         if (c == '\n')
203         {
204             start_line = 1;
205             ++line_no;
206             if (inf_ptr == inf_flsh)
207             {
208                 if (inf_eof)
209                     break;
210                 ++line_no;
211                 if (inf_flush (fd))
212                 {
213                     fprintf (stderr, "%s: read error\n", prog);
214                     return -1;
215                 }
216             }
217         }
218         else
219             start_line = 0;
220     }
221     return 0;
222 }
223
224 int agrep (dfas, fd)
225 struct DFA_state **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);
235
236     ifree (inf_buf);
237     return 0;
238 }
239
240
241 int main (argc, argv)
242 int argc;
243 char **argv;
244 {
245     const char *pattern = NULL;
246     char outbuf[BUFSIZ];
247     int fd, i, no = 0;
248     struct DFA *dfa = dfa_init();
249
250     prog = *argv;
251     if (argc < 2)
252     {
253         fprintf (stderr, "usage: agrep [options] pattern file..\n");
254         fprintf (stderr, " -v   dfa verbose\n");
255         fprintf (stderr, " -n   show lines\n");
256         fprintf (stderr, " -d   debug\n");
257         fprintf (stderr, " -V   show version\n");
258         exit (1);
259     }
260     setbuf (stdout, outbuf);
261     i = agrep_options (argc, argv);
262     if (i)
263         return i;
264     while (--argc > 0)
265         if (**++argv != '-' && **argv)
266         {
267             if (!pattern)
268             {
269                 pattern = *argv;
270                 i = dfa_parse (dfa, &pattern);
271                 if (i || *pattern)
272                 {
273                     fprintf (stderr, "%s: illegal pattern\n", prog);
274                     return 1;
275                 }
276                 dfa_mkstate (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 (dfa->states, fd);
288                 close (fd);
289                 if (i)
290                     return i;
291             }
292         }
293     if (!no)
294     {
295         fprintf (stderr, "usage:\n "
296                          " %s [-d] [-v] [-n] [-f] pattern file ..\n", prog);
297         return 2;
298     }
299     fflush(stdout);
300     dfa_delete (&dfa);
301     return 0;
302 }