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