RPA Toolkit
Fixed REX_DFA_NEXT macro.
[rpatk.git] / rexgrep / rexgrep.c
1 /*
2  *  Regular Pattern Analyzer Toolkit (RPA/Tk)
3  *  Copyright (c) 2009-2012 Martin Stoilov
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  *  Martin Stoilov <martin@rpasearch.com>
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26
27 /*
28  * Temporary here. Need to fix the encoding definitions.
29  */
30 #include "rpa/rpastat.h"
31
32 #include "rlib/rutf.h"
33 #include "rlib/rmem.h"
34 #include "rex/rextransition.h"
35 #include "rex/rexdfasimulator.h"
36 #include "rexgrep.h"
37 #include "rexgrepdep.h"
38
39 #define MAX_STACK 256000
40
41
42
43 rexgrep_t *rex_grep_create()
44 {
45         rexgrep_t *pGrep;
46         
47         pGrep = (rexgrep_t *)r_malloc(sizeof(*pGrep));
48         if (!pGrep)
49                 return (void *)0;
50         r_memset(pGrep, 0, sizeof(*pGrep));
51         pGrep->nfa = rex_db_create(REXDB_TYPE_NFA);
52         pGrep->si = rex_nfasimulator_create();
53         pGrep->dfasi = rex_dfasimulator_create();
54         pGrep->ret = 1;
55         pGrep->startuid = 0UL;
56         return pGrep;
57 }
58
59
60 void rex_grep_destroy(rexgrep_t *pGrep)
61 {
62         if (!pGrep)
63                 return;
64         rex_db_destroy(pGrep->nfa);
65         rex_dfa_destroy(pGrep->dfa);
66         rex_nfasimulator_destroy(pGrep->si);
67         rex_dfasimulator_destroy(pGrep->dfasi);
68         r_free(pGrep);
69 }
70
71
72 int rex_grep_load_string_pattern(rexgrep_t *pGrep, rbuffer_t *buf)
73 {
74         return rex_grep_load_pattern(pGrep, buf);
75 }
76
77
78 int rex_grep_load_pattern(rexgrep_t *pGrep, rbuffer_t *buf)
79 {
80         pGrep->startuid = rex_db_addexpression(pGrep->nfa, pGrep->startuid, buf->s, buf->size, 0);
81         if (pGrep->startuid < 0) {
82                 return -1;
83         }
84         return 0;
85 }
86
87
88 int rex_grep_match(rexgrep_t *pGrep, const char* input, const char *end)
89 {
90         int inc;
91         ruint32 wc;
92         rexdb_t *db;
93
94         if (pGrep->usedfa) {
95                 ruint32 wc = 0;
96                 int ret = 0;
97                 long nstate = REX_DFA_STARTSTATE;
98                 const char *start = input;
99                 rexdfa_t *dfa = pGrep->dfa;
100                 rexdfs_t *s;
101
102                 while ((inc = r_utf8_mbtowc(&wc, (const unsigned char*)input, (const unsigned char*)end)) > 0) {
103                         REX_DFA_NEXT(dfa, nstate, wc, &nstate);
104                         if (nstate == 0)
105                                 break;
106                         input += inc;
107                         s = REX_DFA_STATE(dfa, nstate);
108                         if (s->type == REX_STATETYPE_ACCEPT)
109                                 ret = input - start;
110                 }
111                 return ret;
112         }
113
114         if (pGrep->startuid < 0) {
115                 return -1;
116         }
117         db = pGrep->nfa;
118
119         rex_nfasimulator_start(pGrep->si, db, pGrep->startuid);
120         while ((inc = r_utf8_mbtowc(&wc, (const unsigned char*)input, (const unsigned char*)end)) > 0) {
121                 if (rex_nfasimulator_next(pGrep->si, db, wc, inc) == 0)
122                         break;
123                 input += inc;
124         }
125         if (r_array_length(pGrep->si->accepts) > 0) {
126                 rex_accept_t *acc = (rex_accept_t *)r_array_lastslot(pGrep->si->accepts);
127                 return acc->inputsize;
128         }
129         return 0;
130 }
131
132
133 int rex_grep_scan(rexgrep_t *pGrep, const char* start, const char* end)
134 {
135         int ret = 0;
136
137         while (start < end) {
138                 ret = rex_grep_match(pGrep, start, end);
139                 if (ret < 0) {
140                         /*
141                          * Error
142                          */
143                         return -1;
144                 } else if (ret > 0) {
145                         if (pGrep->showfilename) {
146                                 fprintf(stdout, "%s:", (const char*)pGrep->filename);
147                         }
148                         fwrite(start, 1, ret, stdout);
149                         fprintf(stdout, "\n");
150                         start += ret;
151                 } else {
152                         ruint32 wc;
153                         if ((ret = r_utf8_mbtowc(&wc, (const unsigned char*)start, (const unsigned char*)end)) <= 0)
154                                 ret = 1;
155                         start += ret;
156                 }
157         }
158         return 0;
159 }
160
161
162 static int rex_grep_scan_do(rexgrep_t *pGrep, const char* start, const char* end)
163 {
164         int ret = 0;
165
166         while (start < end) {
167                 ret = rex_grep_match(pGrep, start, end);
168                 if (ret < 0) {
169                         /*
170                          * Error
171                          */
172                         return -1;
173                 } else if (ret > 0) {
174                         return ret;
175                 } else {
176                         ruint32 wc;
177                         if ((ret = r_utf8_mbtowc(&wc, (const unsigned char*)start, (const unsigned char*)end)) <= 0)
178                                 ret = 1;
179                         start += ret;
180                 }
181         }
182         return 0;
183 }
184
185
186 int rex_grep_scan_lines(rexgrep_t *pGrep, const char* start, const char* end)
187 {
188         int ret;
189         const char *eol;
190
191         for (eol = start; eol < end; eol++) {
192                 if (*eol == '\n' || (eol + 1) == end) {
193                         ret = rex_grep_scan_do(pGrep, start, eol + 1);
194                         if (ret > 0) {
195                                 if (pGrep->showfilename) {
196                                         fprintf(stdout, "%s:", (const char*)pGrep->filename);
197                                 }
198                                 fwrite(start, 1, eol + 1 - start, stdout);
199                         }
200                         start = eol + 1;
201                 }
202         }
203         rex_grep_output_utf8_string(pGrep, "\n");
204         return 0;
205 }
206
207
208 void rex_grep_scan_buffer(rexgrep_t *pGrep, rbuffer_t *buf)
209 {
210         switch (pGrep->greptype) {
211         case REX_GREPTYPE_SCANLINES:
212                 rex_grep_scan_lines(pGrep, buf->s, buf->s + buf->size);
213                 break;
214         case REX_GREPTYPE_MATCH:
215         case REX_GREPTYPE_SCAN:
216         default:
217                 rex_grep_scan(pGrep, buf->s, buf->s + buf->size);
218                 break;
219         };
220 }
221
222
223 void rex_grep_output(rexgrep_t *pGrep, const char *s, unsigned long size, unsigned int encoding)
224 {
225         const unsigned char *input = (const unsigned char*)s;
226         const unsigned char *end = input + size;
227         unsigned int wc;
228         int ret;
229
230         if (encoding == RPA_ENCODING_UTF16LE || encoding == RPA_ENCODING_ICASE_UTF16LE) {
231                 while ((ret = (int)r_utf16_mbtowc(&wc, input, end)) != 0) {
232                         rex_grep_output_char(wc);
233                         input += ret;
234                 }
235         } else {
236                 while ((ret = (int)r_utf8_mbtowc(&wc, input, end)) != 0) {
237                         rex_grep_output_char(wc);
238                         input += ret;
239                 }
240         }
241 }
242
243
244 void rex_grep_output_utf8_string(rexgrep_t *pGrep, const char *s)
245 {
246         rex_grep_output(pGrep, s, r_strlen(s), RPA_ENCODING_UTF8);
247 }
248
249
250 void rex_grep_output_utf16_string(rexgrep_t *pGrep, const unsigned short *s)
251 {
252         unsigned long size = 0;
253         const unsigned short *pstr = s;
254
255         while (*pstr) {
256                 size += sizeof(unsigned short);
257                 pstr += 1;
258         }
259         rex_grep_output(pGrep, (const char*)s, size, RPA_ENCODING_UTF16LE);
260 }