RPA Toolkit
ad90f0928ab868a89e71d6c8b7deffc67f82c099
[rpatk.git] / rgrep / rpagrep.c
1 /*
2  *  Regular Pattern Analyzer (RPA)
3  *  Copyright (c) 2009-2010 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 #include "rpagrep.h"
28 #include "rpagreputf.h"
29 #include "rpagrepdep.h"
30
31 #define MAX_STACK 256000
32
33 rpa_buffer_t * rpa_buffer_init(rpa_buffer_t *str, char *s, unsigned int size)
34 {
35         str->s = s;
36         str->size = size;
37         return str;
38 }
39
40
41 void rpa_buffer_free(rpa_buffer_t *str)
42 {
43         if (str) {
44                 free(str->s);
45                 free(str);
46         }       
47 }
48
49
50 rpa_buffer_t * rpa_buffer_alloc(unsigned int size)
51 {
52         rpa_buffer_t * str;
53
54         str = (rpa_buffer_t *)malloc(sizeof(rpa_buffer_t));
55         if (!str)
56                 return (void*)0;
57         memset(str, 0, sizeof(*str));
58         if (!(str->s = (char *)malloc((size + 1) * sizeof(char)))) {
59                 free(str);
60                 return (void*)0;
61         }
62         memset(str->s, 0, size + 1);
63         str->size = size;
64         str->destroy = rpa_buffer_free;
65         return str;
66 }
67
68
69 int rpa_buffer_realloc(rpa_buffer_t *str, unsigned int size)
70 {
71         char *s;
72
73         s = (char *)realloc(str->s, size);
74         if (!s)
75                 return -1;
76         str->s = s;
77         str->size = size;
78         return 0;
79 }
80
81
82 void rpa_buffer_destroy(rpa_buffer_t *str)
83 {
84         if (str && str->destroy)
85                 str->destroy(str);      
86 }
87
88
89 rpa_grep_t *rpa_grep_create()
90 {
91         rpa_grep_t *pGrep;
92         
93         pGrep = (rpa_grep_t *)malloc(sizeof(*pGrep));
94         if (!pGrep)
95                 return (void *)0;
96         memset(pGrep, 0, sizeof(*pGrep));
97         pGrep->hDbex = rpa_dbex_create();
98         return pGrep;
99 }
100
101 void rpa_grep_close(rpa_grep_t *pGrep)
102 {
103         if (pGrep->hDbex)
104                 rpa_dbex_destroy(pGrep->hDbex);
105         pGrep->hDbex = 0;       
106 }
107
108
109 void rpa_grep_optimizations(rpa_grep_t *pGrep, rulong allow)
110 {
111         rpa_dbex_cfgset(pGrep->hDbex, RPA_DBEXCFG_OPTIMIZATIONS, allow);
112 }
113
114
115 void rpa_grep_destroy(rpa_grep_t *pGrep)
116 {
117         if (!pGrep)
118                 return;
119         rpa_grep_close(pGrep);
120         free(pGrep);
121 }
122
123
124 int rpa_grep_load_string_pattern(rpa_grep_t *pGrep, rpa_buffer_t *buf)
125 {
126         return rpa_grep_load_pattern(pGrep, buf);
127 }
128
129
130 int rpa_grep_load_pattern(rpa_grep_t *pGrep, rpa_buffer_t *buf)
131 {
132         int ret, line;
133         int inputsize = buf->size;
134         const char *pattern = buf->s;
135
136         if (rpa_dbex_open(pGrep->hDbex) < 0) {
137                 fprintf(stdout, "Failed to open rules database.\n");
138                 goto error;
139         }
140
141         while ((ret = rpa_dbex_load(pGrep->hDbex, pattern, inputsize)) > 0) {
142                 inputsize -= ret;
143                 pattern += ret;
144         }
145         if (ret < 0) {
146                 rpa_errinfo_t errinfo;
147                 rpa_dbex_getlasterrinfo(pGrep->hDbex, &errinfo);
148                 if (errinfo.code == RPA_E_SYNTAX_ERROR) {
149                         pattern += errinfo.offset;
150                         for (line = 1; pattern >= buf->s; --pattern) {
151                                 if (*pattern == '\n')
152                                         line += 1;
153                         }
154                         fprintf(stdout, "Line: %d, ERROR: Syntax Error.\n", line);
155                 } else {
156                         fprintf(stdout, "ERROR: Pattern Loading failed.\n");
157                 }
158                 goto error;
159         }       
160         
161         rpa_dbex_close(pGrep->hDbex);
162         pGrep->hPattern = rpa_dbex_default(pGrep->hDbex);
163         return 0;
164         
165 error:
166         rpa_dbex_close(pGrep->hDbex);
167         return -1;
168 }
169
170
171 void rpa_grep_list_patterns(rpa_grep_t *pGrep)
172 {
173         rpa_dbex_dumprules(pGrep->hDbex);
174 }
175
176
177 void rpa_grep_dump_pattern_records(rpa_grep_t *pGrep)
178 {
179         rpa_dbex_dumprecords(pGrep->hDbex);
180 }
181
182
183 void rpa_grep_dump_pattern_info(rpa_grep_t *pGrep)
184 {
185         rpa_dbex_compile(pGrep->hDbex);
186         rpa_dbex_dumpinfo(pGrep->hDbex);
187 }
188
189
190 void rpa_grep_dump_alias_info(rpa_grep_t *pGrep)
191 {
192         rpa_dbex_compile(pGrep->hDbex);
193         rpa_dbex_dumpalias(pGrep->hDbex);
194 }
195
196
197 int rpa_grep_match(rpa_grep_t *pGrep, const char* buffer, unsigned long size)
198 {
199         int ret = 0;
200         rpastat_t *hStat;
201         const char *input = buffer, *start = buffer, *end = buffer + size;
202
203         hStat = rpa_stat_create(pGrep->hDbex, 0);
204         if (!hStat)
205                 return -1;
206         rpa_stat_encodingset(hStat, pGrep->encoding);
207         hStat->debug = pGrep->execdebug;
208         ret = rpa_stat_match(hStat, pGrep->hPattern, input, start, end);
209         if (ret > 0) {
210                 rpa_grep_print_filename(pGrep);
211                 rpa_grep_output(pGrep, input, ret, pGrep->encoding);
212                 rpa_grep_output_utf8_string(pGrep, "\n");
213         }
214         pGrep->cachehit = hStat->cache->hit;
215         rpa_stat_destroy(hStat);
216         return 0;
217 }
218
219
220 int rpa_grep_parse(rpa_grep_t *pGrep, const char* buffer, unsigned long size)
221 {
222         rlong i;
223         rchar location[128];
224         rpastat_t *hStat;
225         rarray_t *records = NULL;
226         rparecord_t *prec;
227         const char *input = buffer, *start = buffer, *end = buffer + size;
228
229         hStat = rpa_stat_create(pGrep->hDbex, 0);
230         if (!hStat)
231                 return -1;
232         rpa_stat_encodingset(hStat, pGrep->encoding);
233         hStat->debug = pGrep->execdebug;
234         rpa_stat_parse(hStat, pGrep->hPattern, input, start, end, &records);
235         if (records) {
236                 if (pGrep->greptype == RPA_GREPTYPE_PARSE) {
237                         for (i = 0; i < r_array_length(records); i++) {
238                                 prec = (rparecord_t *)r_array_slot(records, i);
239                                 if (prec->type & RPA_RECORD_END) {
240                                         rpa_grep_output_utf8_string(pGrep, prec->rule);
241                                         r_snprintf(location, sizeof(location), " (%ld, %ld)", (rlong)(prec->input - input), (rlong)prec->inputsiz);
242                                         rpa_grep_output_utf8_string(pGrep, location);
243                                         rpa_grep_output_utf8_string(pGrep, ": ");
244                                         rpa_grep_output(pGrep, prec->input, prec->inputsiz, pGrep->encoding);
245                                         rpa_grep_output_utf8_string(pGrep, "\n");
246                                 }
247                         }
248                 } else if (pGrep->greptype == RPA_GREPTYPE_PARSEAST) {
249                         for (i = 0; i < r_array_length(records); i++) {
250                                 rpa_record_dump(records, i);
251                         }
252
253                 }
254                 r_array_destroy(records);
255         }
256         pGrep->cachehit = hStat->cache->hit;
257         rpa_stat_destroy(hStat);
258         return 0;
259 }
260
261
262 int rpa_grep_scan(rpa_grep_t *pGrep, const char* buffer, unsigned long size)
263 {
264         int ret = 0;
265         rpastat_t *hStat;
266         int displayed = 0;      
267         const char *matched;
268         const char *input = buffer, *start = buffer, *end = buffer + size;
269
270         hStat = rpa_stat_create(pGrep->hDbex, 0);
271         if (!hStat)
272                 return -1;
273         rpa_stat_encodingset(hStat, pGrep->encoding);
274         hStat->debug = pGrep->execdebug;
275         pGrep->cachehit = hStat->cache->hit;
276
277 again:
278         ret = rpa_stat_scan(hStat, pGrep->hPattern, input, start, end, &matched);
279         pGrep->cachehit += hStat->cache->hit;
280         if (ret > 0) {
281                 if (!displayed) {
282                         displayed = 1;
283                         rpa_grep_print_filename(pGrep);
284                 }
285                 rpa_grep_output(pGrep, matched, ret, pGrep->encoding);
286                 rpa_grep_output_utf8_string(pGrep, "\n");
287         }
288         if (ret && matched + ret < end) {
289                 input = matched + ret;
290                 goto again;
291         }
292
293         rpa_stat_destroy(hStat);
294         return 0;
295 }
296
297
298 int rpa_grep_scan_lines(rpa_grep_t *pGrep, const char* buffer, unsigned long size)
299 {
300         int ret = 0;
301         rpastat_t *hStat;
302         const char *matched;
303         int displayed = 0;
304         unsigned long lines = 0;
305         const char *end = buffer + size, *lstart = buffer, *lend;
306
307         hStat = rpa_stat_create(pGrep->hDbex, 0);
308         if (!hStat)
309                 return -1;
310         rpa_stat_encodingset(hStat, pGrep->encoding);
311         hStat->debug = pGrep->execdebug;
312         
313 again:
314         if (pGrep->encoding == RPA_ENCODING_UTF16LE || pGrep->encoding == RPA_ENCODING_ICASE_UTF16LE) {
315                 for (lend = lstart; lend < end; lend += sizeof(unsigned short)) {
316                         if (*((unsigned short*)lend) == L'\n') {
317                                 ++lines;
318                                 lend += sizeof(unsigned short);
319                                 break;
320                         }
321                 }
322         } else {
323                 for (lend = lstart; lend < end; lend += sizeof(unsigned char)) {
324                         if (*((unsigned char*)lend) == '\n') {
325                                 ++lines;
326                                 lend += sizeof(unsigned char);
327                                 break;
328                         }
329                 }
330         }
331         if (!lines)
332                 return 0;
333         ret = rpa_stat_scan(hStat, pGrep->hPattern, lstart, lstart, lend, &matched);
334         if (ret > 0) {
335                 if (!displayed) {
336                         displayed = 1;
337                         rpa_grep_print_filename(pGrep);
338                 }
339                 rpa_grep_output(pGrep, lstart, lend - lstart, pGrep->encoding);
340         }
341         if (lend < end) {
342                 lstart = lend;
343                 goto again;
344         }
345         rpa_stat_destroy(hStat);
346         return 0;
347 }
348
349
350 void rpa_grep_scan_buffer(rpa_grep_t *pGrep, rpa_buffer_t *buf)
351 {
352         const char *input;
353         unsigned long size;
354         clock_t btime, scanclocks;
355
356         if (pGrep->forceEncoding == RPA_GREP_FORCE_BYTE) {
357                 input = buf->s;
358                 size = buf->size;
359                 pGrep->encoding =  pGrep->icase ? RPA_ENCODING_ICASE_BYTE : RPA_ENCODING_BYTE;
360         } else if (pGrep->forceEncoding == RPA_GREP_FORCE_UTF16) {
361                 if (buf->size >= 2 && buf->s[0] == -1 && buf->s[1] == -2) {
362                         input = buf->s + 2;
363                         size = buf->size - 2;
364                 } else {
365                         input = buf->s;
366                         size = buf->size;
367                 }
368                 pGrep->encoding =  pGrep->icase ? RPA_ENCODING_ICASE_UTF16LE : RPA_ENCODING_UTF16LE;
369         } else if (buf->size >= 2 && buf->s[0] == -1 && buf->s[1] == -2) {
370                 input = buf->s + 2;
371                 size = buf->size - 2;
372                 pGrep->encoding =  pGrep->icase ? RPA_ENCODING_ICASE_UTF16LE : RPA_ENCODING_UTF16LE;
373         } else {
374                 pGrep->encoding = pGrep->icase ? RPA_ENCODING_ICASE_UTF8 : RPA_ENCODING_UTF8;
375                 input = buf->s;
376                 size = buf->size;
377         }               
378
379         btime = clock();
380
381         switch (pGrep->greptype) {
382         case RPA_GREPTYPE_SCANLINES:
383                 rpa_grep_scan_lines(pGrep, input, size);
384                 break;
385         case RPA_GREPTYPE_MATCH:
386                 rpa_grep_match(pGrep, input, size);
387                 break;
388         case RPA_GREPTYPE_PARSEAST:
389         case RPA_GREPTYPE_PARSE:
390                 rpa_grep_parse(pGrep, input, size);
391                 break;
392         case RPA_GREPTYPE_SCAN:
393                 rpa_grep_scan(pGrep, input, size);
394                 break;
395         default:
396                 rpa_grep_scan(pGrep, input, size);
397                 break;
398         };
399
400         scanclocks = clock() - btime;
401         pGrep->scanmilisec += (unsigned long)(((unsigned long long)1000)*scanclocks/CLOCKS_PER_SEC);
402 }
403
404
405 rpa_buffer_t *rpa_buffer_loadfile(FILE *pFile)
406 {
407         unsigned int memchunk = 256;
408         int ret = 0, inputsize = 0;
409         rpa_buffer_t *buf;
410         
411         buf = rpa_buffer_alloc(2 * memchunk);
412         if (!buf)
413                 return (void*)0;
414         
415         do {
416                 if ((buf->size - inputsize) < memchunk) {
417                         if (rpa_buffer_realloc(buf, buf->size + memchunk) < 0) {
418                                 fprintf(stderr, "Out of memory!\n");
419                                 exit(1);
420                         }
421                 }
422                 ret = fread(&buf->s[inputsize], 1, memchunk - 1, pFile);
423                 if ((ret <= 0) && ferror(pFile)) {
424                         rpa_buffer_destroy(buf);
425                         return (void*)0;
426                 }
427                 inputsize += ret;
428                 buf->s[inputsize] = '\0';
429                 buf->size = inputsize;
430         } while (!feof(pFile)); 
431         
432         return buf;
433 }
434
435
436 int rpa_callback_output(rpastat_t * stat, const char *name, void *userdata, const char *input, unsigned int size, unsigned int reason)
437 {
438
439         return size;
440 }
441
442
443 int rpa_callback_matched_output(rpastat_t * stat, const char *name, void *userdata, const char *input, unsigned int size, unsigned int reason)
444 {
445         rpa_grep_t *pGrep = (rpa_grep_t *)userdata;
446
447         rpa_grep_output_utf8_string(pGrep, name);
448         rpa_grep_output_utf8_string(pGrep, ": ");
449         rpa_grep_output(pGrep, input, size, pGrep->encoding);
450         rpa_grep_output_utf8_string(pGrep, "\n");
451
452         return size;
453 }
454
455
456 void rpa_grep_setup_callback(rpa_grep_t *pGrep, rpa_buffer_t *pattern)
457 {
458
459 }
460
461
462 void rpa_grep_setup_matched_callback(rpa_grep_t *pGrep, rpa_buffer_t *pattern)
463 {
464
465 }
466
467
468 void rpa_grep_dump_pattern_tree(rpa_grep_t *pGrep, rpa_buffer_t *pattern)
469 {
470         rpa_dbex_dumptree_s(pGrep->hDbex, pattern->s, 0);
471 }
472
473
474 void rpa_grep_output(rpa_grep_t *pGrep, const char *s, unsigned long size, unsigned int encoding)
475 {
476         const unsigned char *input = (const unsigned char*)s;
477         const unsigned char *end = input + size;
478         unsigned int wc;
479         int ret;
480         
481         if (encoding == RPA_ENCODING_UTF16LE || encoding == RPA_ENCODING_ICASE_UTF16LE) {
482                 while ((ret = (int)rpa_grep_utf16_mbtowc(&wc, input, end)) != 0) {
483                         rpa_grep_output_char(wc);
484                         input += ret;
485                 }
486         } else {
487                 while ((ret = (int)rpa_grep_utf8_mbtowc(&wc, input, end)) != 0) {
488                         rpa_grep_output_char(wc);
489                         input += ret;
490                 }
491         }
492 }
493
494
495 void rpa_grep_output_utf8_string(rpa_grep_t *pGrep, const char *s)
496 {
497         rpa_grep_output(pGrep, s, strlen(s), RPA_ENCODING_UTF8);
498 }
499
500
501 void rpa_grep_output_utf16_string(rpa_grep_t *pGrep, const unsigned short *s)
502 {
503         unsigned long size = 0;
504         const unsigned short *pstr = s;
505
506         while (*pstr) {
507                 size += sizeof(unsigned short);
508                 pstr += 1;
509         }
510         rpa_grep_output(pGrep, (const char*)s, size, RPA_ENCODING_UTF16LE);
511 }