RPA Toolkit
984cac08e3cad0863d6e66c7ba90303a1fd7b766
[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_lasterrorinfo(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_last(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_cachedisable(hStat, pGrep->disablecache);
207         rpa_stat_encodingset(hStat, pGrep->encoding);
208         hStat->debug = pGrep->execdebug;
209         ret = rpa_stat_match(hStat, pGrep->hPattern, input, start, end);
210         if (ret > 0) {
211                 rpa_grep_print_filename(pGrep);
212                 rpa_grep_output(pGrep, input, ret, pGrep->encoding);
213                 rpa_grep_output_utf8_string(pGrep, "\n");
214         }
215         pGrep->cachehit = hStat->cache->hit;
216         pGrep->orphrecords = r_array_length(hStat->orphans);
217         pGrep->emitstacksize = r_array_length(hStat->emitstack);
218
219         rpa_stat_destroy(hStat);
220         return 0;
221 }
222
223
224 int rpa_grep_parse(rpa_grep_t *pGrep, const char* buffer, unsigned long size)
225 {
226         rlong i;
227         rchar location[128];
228         rpastat_t *hStat;
229         rarray_t *records = NULL;
230         rparecord_t *prec;
231         const char *input = buffer, *start = buffer, *end = buffer + size;
232
233         hStat = rpa_stat_create(pGrep->hDbex, 0);
234         if (!hStat)
235                 return -1;
236         rpa_stat_cachedisable(hStat, pGrep->disablecache);
237         rpa_stat_encodingset(hStat, pGrep->encoding);
238         hStat->debug = pGrep->execdebug;
239         rpa_stat_parse(hStat, pGrep->hPattern, input, start, end, &records);
240         if (records) {
241                 if (pGrep->greptype == RPA_GREPTYPE_PARSE) {
242                         for (i = 0; i < r_array_length(records); i++) {
243                                 prec = (rparecord_t *)r_array_slot(records, i);
244                                 if (prec->type & RPA_RECORD_END) {
245                                         rpa_grep_output_utf8_string(pGrep, prec->rule);
246                                         r_snprintf(location, sizeof(location), " (%ld, %ld)", (rlong)(prec->input - input), (rlong)prec->inputsiz);
247                                         rpa_grep_output_utf8_string(pGrep, location);
248                                         rpa_grep_output_utf8_string(pGrep, ": ");
249                                         rpa_grep_output(pGrep, prec->input, prec->inputsiz, pGrep->encoding);
250                                         rpa_grep_output_utf8_string(pGrep, "\n");
251                                 }
252                         }
253                 } else if (pGrep->greptype == RPA_GREPTYPE_PARSEAST) {
254                         for (i = 0; i < r_array_length(records); i++) {
255                                 rpa_record_dump(records, i);
256                         }
257
258                 }
259                 r_array_destroy(records);
260         }
261         pGrep->cachehit = hStat->cache->hit;
262         pGrep->orphrecords = r_array_length(hStat->orphans);
263         pGrep->emitstacksize = r_array_length(hStat->emitstack);
264
265         rpa_stat_destroy(hStat);
266         return 0;
267 }
268
269
270 int rpa_grep_scan(rpa_grep_t *pGrep, const char* buffer, unsigned long size)
271 {
272         int ret = 0;
273         rpastat_t *hStat;
274         int displayed = 0;      
275         const char *matched;
276         const char *input = buffer, *start = buffer, *end = buffer + size;
277
278         hStat = rpa_stat_create(pGrep->hDbex, 0);
279         if (!hStat)
280                 return -1;
281         rpa_stat_encodingset(hStat, pGrep->encoding);
282         rpa_stat_cachedisable(hStat, pGrep->disablecache);
283         hStat->debug = pGrep->execdebug;
284         pGrep->cachehit = hStat->cache->hit;
285         pGrep->orphrecords = r_array_length(hStat->orphans);
286
287 again:
288         ret = rpa_stat_scan(hStat, pGrep->hPattern, input, start, end, &matched);
289         pGrep->cachehit += hStat->cache->hit;
290         pGrep->orphrecords += r_array_length(hStat->orphans);
291
292         if (ret > 0) {
293                 if (!displayed) {
294                         displayed = 1;
295                         rpa_grep_print_filename(pGrep);
296                 }
297                 rpa_grep_output(pGrep, matched, ret, pGrep->encoding);
298                 rpa_grep_output_utf8_string(pGrep, "\n");
299         }
300         if (ret && matched + ret < end) {
301                 input = matched + ret;
302                 goto again;
303         }
304
305         pGrep->emitstacksize = r_array_length(hStat->emitstack);
306         rpa_stat_destroy(hStat);
307         return 0;
308 }
309
310
311 int rpa_grep_scan_lines(rpa_grep_t *pGrep, const char* buffer, unsigned long size)
312 {
313         int ret = 0;
314         rpastat_t *hStat;
315         const char *matched;
316         int displayed = 0;
317         unsigned long lines = 0;
318         const char *end = buffer + size, *lstart = buffer, *lend;
319
320         hStat = rpa_stat_create(pGrep->hDbex, 0);
321         if (!hStat)
322                 return -1;
323         rpa_stat_encodingset(hStat, pGrep->encoding);
324         hStat->debug = pGrep->execdebug;
325         
326 again:
327         if (pGrep->encoding == RPA_ENCODING_UTF16LE || pGrep->encoding == RPA_ENCODING_ICASE_UTF16LE) {
328                 for (lend = lstart; lend < end; lend += sizeof(unsigned short)) {
329                         if (*((unsigned short*)lend) == L'\n') {
330                                 ++lines;
331                                 lend += sizeof(unsigned short);
332                                 break;
333                         }
334                 }
335         } else {
336                 for (lend = lstart; lend < end; lend += sizeof(unsigned char)) {
337                         if (*((unsigned char*)lend) == '\n') {
338                                 ++lines;
339                                 lend += sizeof(unsigned char);
340                                 break;
341                         }
342                 }
343         }
344         if (!lines)
345                 return 0;
346         ret = rpa_stat_scan(hStat, pGrep->hPattern, lstart, lstart, lend, &matched);
347         if (ret > 0) {
348                 if (!displayed) {
349                         displayed = 1;
350                         rpa_grep_print_filename(pGrep);
351                 }
352                 rpa_grep_output(pGrep, lstart, lend - lstart, pGrep->encoding);
353         }
354         if (lend < end) {
355                 lstart = lend;
356                 goto again;
357         }
358         rpa_stat_destroy(hStat);
359         return 0;
360 }
361
362
363 void rpa_grep_scan_buffer(rpa_grep_t *pGrep, rpa_buffer_t *buf)
364 {
365         const char *input;
366         unsigned long size;
367         clock_t btime, scanclocks;
368
369         if (pGrep->forceEncoding == RPA_GREP_FORCE_BYTE) {
370                 input = buf->s;
371                 size = buf->size;
372                 pGrep->encoding =  pGrep->icase ? RPA_ENCODING_ICASE_BYTE : RPA_ENCODING_BYTE;
373         } else if (pGrep->forceEncoding == RPA_GREP_FORCE_UTF16) {
374                 if (buf->size >= 2 && buf->s[0] == -1 && buf->s[1] == -2) {
375                         input = buf->s + 2;
376                         size = buf->size - 2;
377                 } else {
378                         input = buf->s;
379                         size = buf->size;
380                 }
381                 pGrep->encoding =  pGrep->icase ? RPA_ENCODING_ICASE_UTF16LE : RPA_ENCODING_UTF16LE;
382         } else if (buf->size >= 2 && buf->s[0] == -1 && buf->s[1] == -2) {
383                 input = buf->s + 2;
384                 size = buf->size - 2;
385                 pGrep->encoding =  pGrep->icase ? RPA_ENCODING_ICASE_UTF16LE : RPA_ENCODING_UTF16LE;
386         } else {
387                 pGrep->encoding = pGrep->icase ? RPA_ENCODING_ICASE_UTF8 : RPA_ENCODING_UTF8;
388                 input = buf->s;
389                 size = buf->size;
390         }               
391
392         btime = clock();
393
394         switch (pGrep->greptype) {
395         case RPA_GREPTYPE_SCANLINES:
396                 rpa_grep_scan_lines(pGrep, input, size);
397                 break;
398         case RPA_GREPTYPE_MATCH:
399                 rpa_grep_match(pGrep, input, size);
400                 break;
401         case RPA_GREPTYPE_PARSEAST:
402         case RPA_GREPTYPE_PARSE:
403                 rpa_grep_parse(pGrep, input, size);
404                 break;
405         case RPA_GREPTYPE_SCAN:
406                 rpa_grep_scan(pGrep, input, size);
407                 break;
408         default:
409                 rpa_grep_scan(pGrep, input, size);
410                 break;
411         };
412
413         scanclocks = clock() - btime;
414         pGrep->scanmilisec += (unsigned long)(((unsigned long long)1000)*scanclocks/CLOCKS_PER_SEC);
415 }
416
417
418 rpa_buffer_t *rpa_buffer_loadfile(FILE *pFile)
419 {
420         unsigned int memchunk = 256;
421         int ret = 0, inputsize = 0;
422         rpa_buffer_t *buf;
423         
424         buf = rpa_buffer_alloc(2 * memchunk);
425         if (!buf)
426                 return (void*)0;
427         
428         do {
429                 if ((buf->size - inputsize) < memchunk) {
430                         if (rpa_buffer_realloc(buf, buf->size + memchunk) < 0) {
431                                 fprintf(stderr, "Out of memory!\n");
432                                 exit(1);
433                         }
434                 }
435                 ret = fread(&buf->s[inputsize], 1, memchunk - 1, pFile);
436                 if ((ret <= 0) && ferror(pFile)) {
437                         rpa_buffer_destroy(buf);
438                         return (void*)0;
439                 }
440                 inputsize += ret;
441                 buf->s[inputsize] = '\0';
442                 buf->size = inputsize;
443         } while (!feof(pFile)); 
444         
445         return buf;
446 }
447
448
449 int rpa_callback_output(rpastat_t * stat, const char *name, void *userdata, const char *input, unsigned int size, unsigned int reason)
450 {
451
452         return size;
453 }
454
455
456 int rpa_callback_matched_output(rpastat_t * stat, const char *name, void *userdata, const char *input, unsigned int size, unsigned int reason)
457 {
458         rpa_grep_t *pGrep = (rpa_grep_t *)userdata;
459
460         rpa_grep_output_utf8_string(pGrep, name);
461         rpa_grep_output_utf8_string(pGrep, ": ");
462         rpa_grep_output(pGrep, input, size, pGrep->encoding);
463         rpa_grep_output_utf8_string(pGrep, "\n");
464
465         return size;
466 }
467
468
469 void rpa_grep_setup_callback(rpa_grep_t *pGrep, rpa_buffer_t *pattern)
470 {
471
472 }
473
474
475 void rpa_grep_setup_matched_callback(rpa_grep_t *pGrep, rpa_buffer_t *pattern)
476 {
477
478 }
479
480
481 void rpa_grep_dump_pattern_tree(rpa_grep_t *pGrep, rpa_buffer_t *pattern)
482 {
483         rpa_dbex_dumptree_s(pGrep->hDbex, pattern->s, 0);
484 }
485
486
487 void rpa_grep_output(rpa_grep_t *pGrep, const char *s, unsigned long size, unsigned int encoding)
488 {
489         const unsigned char *input = (const unsigned char*)s;
490         const unsigned char *end = input + size;
491         unsigned int wc;
492         int ret;
493         
494         if (encoding == RPA_ENCODING_UTF16LE || encoding == RPA_ENCODING_ICASE_UTF16LE) {
495                 while ((ret = (int)rpa_grep_utf16_mbtowc(&wc, input, end)) != 0) {
496                         rpa_grep_output_char(wc);
497                         input += ret;
498                 }
499         } else {
500                 while ((ret = (int)rpa_grep_utf8_mbtowc(&wc, input, end)) != 0) {
501                         rpa_grep_output_char(wc);
502                         input += ret;
503                 }
504         }
505 }
506
507
508 void rpa_grep_output_utf8_string(rpa_grep_t *pGrep, const char *s)
509 {
510         rpa_grep_output(pGrep, s, strlen(s), RPA_ENCODING_UTF8);
511 }
512
513
514 void rpa_grep_output_utf16_string(rpa_grep_t *pGrep, const unsigned short *s)
515 {
516         unsigned long size = 0;
517         const unsigned short *pstr = s;
518
519         while (*pstr) {
520                 size += sizeof(unsigned short);
521                 pstr += 1;
522         }
523         rpa_grep_output(pGrep, (const char*)s, size, RPA_ENCODING_UTF16LE);
524 }