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