0d671ef15296e7e7fbc758ef24b2362036d58787
[idzebra-moved-to-github.git] / dfa / agrep.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2011 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 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
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 #include <io.h>
36 #endif
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include <idzebra/util.h>
42 #include <dfa.h>
43 #include "imalloc.h"
44
45 #ifndef O_BINARY
46 #define O_BINARY 0
47 #endif
48
49 static char *prog;
50
51 void error (const char *format, ...)
52 {
53     va_list argptr;
54     va_start (argptr, format);
55     fprintf (stderr, "%s error: ", prog);
56     (void) vfprintf (stderr, format, argptr);
57     putc ('\n', stderr);
58     exit (1);
59 }
60
61 static int show_lines = 0;
62
63 int agrep_options (int argc, char **argv)
64 {
65     while (--argc > 0)
66         if (**++argv == '-')
67             while (*++*argv)
68             {
69                 switch (**argv)
70                 {
71                 case 'V':
72                     fprintf (stderr, "%s: %s %s\n", prog, __DATE__, __TIME__);
73                     continue;
74                 case 'v':
75                     dfa_verbose = 1;
76                     continue;
77                 case 'n':
78                     show_lines = 1;
79                     continue;
80                 case 'd':
81                     switch (*++*argv)
82                     {
83                     case 's':
84                         debug_dfa_tran = 1;
85                         break;
86                     case 't':
87                         debug_dfa_trav = 1;
88                         break;
89                     case 'f':
90                         debug_dfa_followpos = 1;
91                         break;
92                     default:
93                         --*argv;
94                         debug_dfa_tran = 1;
95                         debug_dfa_followpos = 1;
96                         debug_dfa_trav = 1;
97                     }
98                     continue;
99                 default:
100                     fprintf (stderr, "%s: unknown option `-%s'\n", prog, *argv);
101                     return 1;
102                 }
103                 break;
104             }
105     return 0;
106 }
107
108 #define INF_BUF_SIZE  32768U
109 static char *inf_buf;
110 static char *inf_ptr, *inf_flsh;
111 static int inf_eof, line_no;
112
113 static int inf_flush (int fd)
114 {
115     char *p;
116     unsigned b, r;
117
118     r = (unsigned) (inf_buf+INF_BUF_SIZE - inf_ptr);  /* no of `wrap' bytes */
119     if (r)
120         memcpy (inf_buf, inf_ptr, r);
121     inf_ptr = p = inf_buf + r;
122     b = INF_BUF_SIZE - r;
123     do
124         if ((r = read (fd, p, b)) == (unsigned) -1)
125             return -1;
126         else if (r)
127             p +=  r;
128         else
129         {
130             *p++ = '\n';
131             inf_eof = 1;
132             break;
133         }
134     while ((b -= r) > 0);
135     while (p != inf_buf && *--p != '\n')
136         ;
137     while (p != inf_buf && *--p != '\n')
138         ;
139     inf_flsh = p+1;
140     return 0;
141 }
142
143 static char *prline (char *p)
144 {
145     char *p0;
146
147     --p;
148     while (p != inf_buf && p[-1] != '\n')
149         --p;
150     p0 = p;
151     while (*p++ != '\n')
152         ;
153     p[-1] = '\0';
154     if (show_lines)
155         printf ("%5d:\t%s\n", line_no, p0);
156     else
157         puts (p0);
158     p[-1] = '\n';
159     return p;
160 }
161
162 static int go (int fd, struct DFA_state **dfaar)
163 {
164     struct DFA_state *s = dfaar[0];
165     struct DFA_tran *t;
166     char *p;
167     int i;
168     unsigned char c;
169     int start_line = 1;
170
171     while (1)
172     {
173         for (c = *inf_ptr++, t=s->trans, i=s->tran_no; --i >= 0; t++)
174             if (c >= t->ch[0] && c <= t->ch[1])
175             {
176                 p = inf_ptr;
177                 do
178                 {
179                     if ((s = dfaar[t->to])->rule_no &&
180                         (start_line || s->rule_nno))
181                     {
182                         inf_ptr = prline (inf_ptr);
183                         c = '\n';
184                         break;
185                     }
186                     for (t=s->trans, i=s->tran_no; --i >= 0; t++)
187                         if ((unsigned) *p >= t->ch[0] 
188                            && (unsigned) *p <= t->ch[1])
189                             break;
190                     p++;
191                 } while (i >= 0);
192                 s = dfaar[0];
193                 break;
194             }
195         if (c == '\n')
196         {
197             start_line = 1;
198             ++line_no;
199             if (inf_ptr == inf_flsh)
200             {
201                 if (inf_eof)
202                     break;
203                 ++line_no;
204                 if (inf_flush (fd))
205                 {
206                     fprintf (stderr, "%s: read error\n", prog);
207                     return -1;
208                 }
209             }
210         }
211         else
212             start_line = 0;
213     }
214     return 0;
215 }
216
217 int agrep (struct DFA_state **dfas, int fd)
218 {
219     inf_buf = imalloc (sizeof(char)*INF_BUF_SIZE);
220     inf_eof = 0;
221     inf_ptr = inf_buf+INF_BUF_SIZE;
222     inf_flush (fd);
223     line_no = 1;
224
225     go (fd, dfas);
226
227     ifree (inf_buf);
228     return 0;
229 }
230
231
232 int main (int argc, char **argv)
233 {
234     const char *pattern = NULL;
235     char outbuf[BUFSIZ];
236     int fd, i, no = 0;
237     struct DFA *dfa = dfa_init();
238
239     prog = *argv;
240     if (argc < 2)
241     {
242         fprintf (stderr, "usage: agrep [options] pattern file..\n");
243         fprintf (stderr, " -v   dfa verbose\n");
244         fprintf (stderr, " -n   show lines\n");
245         fprintf (stderr, " -d   debug\n");
246         fprintf (stderr, " -V   show version\n");
247         exit (1);
248     }
249     setbuf (stdout, outbuf);
250     i = agrep_options (argc, argv);
251     if (i)
252         return i;
253     while (--argc > 0)
254         if (**++argv != '-' && **argv)
255         {
256             if (!pattern)
257             {
258                 pattern = *argv;
259                 i = dfa_parse (dfa, &pattern);
260                 if (i || *pattern)
261                 {
262                     fprintf (stderr, "%s: illegal pattern\n", prog);
263                     return 1;
264                 }
265                 dfa_mkstate (dfa);
266             }
267             else
268             {
269                 ++no;
270                 fd = open (*argv, O_RDONLY | O_BINARY);
271                 if (fd == -1)
272                 {
273                     fprintf (stderr, "%s: couldn't open `%s'\n", prog, *argv);
274                     return 1;
275                 }
276                 i = agrep (dfa->states, fd);
277                 close (fd);
278                 if (i)
279                     return i;
280             }
281         }
282     if (!no)
283     {
284         fprintf (stderr, "usage:\n "
285                          " %s [-d] [-v] [-n] [-f] pattern file ..\n", prog);
286         return 2;
287     }
288     fflush(stdout);
289     dfa_delete (&dfa);
290     return 0;
291 }
292 /*
293  * Local variables:
294  * c-basic-offset: 4
295  * c-file-style: "Stroustrup"
296  * indent-tabs-mode: nil
297  * End:
298  * vim: shiftwidth=4 tabstop=8 expandtab
299  */
300