RPA Toolkit
Changed bitmap display options
[rpatk.git] / rpa / rparecord.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 #include "rlib/rmem.h"
22 #include "rlib/rstring.h"
23 #include "rpa/rpaparser.h"
24 #include "rpa/rparecord.h"
25
26
27 rparecord_t *rpa_record_get(rarray_t *records, long rec)
28 {
29         rparecord_t *prec;
30
31         if (!records)
32                 return NULL;
33         if (rec < 0 || rec >= r_array_length(records))
34                 return NULL;
35         prec = (rparecord_t *)r_array_slot(records, rec);
36         return prec;
37
38 }
39
40
41 long rpa_recordtree_get(rarray_t *records, long rec, unsigned long type)
42 {
43         long i, s = 0;
44         unsigned int startrec = (type & RPA_RECORD_START) ? 1 : 0;
45         rparecord_t *prec;
46
47         if (rec < 0 || rec >= r_array_length(records))
48                 return -1;
49         prec = (rparecord_t *)r_array_slot(records, rec);
50         if ((prec->type & RPA_RECORD_START)) {
51                 if (startrec)
52                         return rec;
53                 for (s = 0, i = rec; i < r_array_length(records); i++) {
54                         prec = (rparecord_t *)r_array_slot(records, i);
55                         if (prec->type & RPA_RECORD_START)
56                                 ++s;
57                         if (prec->type & RPA_RECORD_END)
58                                 --s;
59                         if (s == 0)
60                                 return i;
61                 }
62         }
63         prec = (rparecord_t *)r_array_slot(records, rec);
64         if ((prec->type & RPA_RECORD_END)) {
65                 if (!startrec)
66                         return rec;
67                 for (s = 0, i = rec; i >= 0; i--) {
68                         prec = (rparecord_t *)r_array_slot(records, i);
69                         if (prec->type & RPA_RECORD_START)
70                                 ++s;
71                         if (prec->type & RPA_RECORD_END)
72                                 --s;
73                         if (s == 0)
74                                 return i;
75                 }
76         }
77
78         return -1;
79 }
80
81
82 long rpa_recordtree_firstchild(rarray_t *records, long rec, unsigned long type)
83 {
84         rparecord_t *prec;
85
86         if (rec < 0 || rec >= r_array_length(records))
87                 return -1;
88         prec = (rparecord_t *)r_array_slot(records, rec);
89         if (prec->type & RPA_RECORD_END) {
90                 if ((rec = rpa_recordtree_get(records, rec, RPA_RECORD_START)) < 0)
91                         return -1;
92         }
93         if (++rec >= r_array_length(records))
94                 return -1;
95         prec = (rparecord_t *)r_array_slot(records, rec);
96         if (prec->type & RPA_RECORD_START)
97                 return rpa_recordtree_get(records, rec, type);
98         return -1;
99 }
100
101
102 long rpa_recordtree_lastchild(rarray_t *records, long rec, unsigned long type)
103 {
104         rparecord_t *prec;
105
106         if (rec < 0 || rec >= r_array_length(records))
107                 return -1;
108         prec = (rparecord_t *)r_array_slot(records, rec);
109         if (prec->type & RPA_RECORD_START) {
110                 if ((rec = rpa_recordtree_get(records, rec, RPA_RECORD_END)) < 0)
111                         return -1;
112         }
113         if (--rec < 0)
114                 return -1;
115         prec = (rparecord_t *)r_array_slot(records, rec);
116         if (prec->type & RPA_RECORD_END)
117                 return rpa_recordtree_get(records, rec, type);
118         return -1;
119 }
120
121
122 long rpa_recordtree_next(rarray_t *records, long rec, unsigned long type)
123 {
124         rparecord_t *prec;
125
126         if (rec < 0 || rec >= r_array_length(records))
127                 return -1;
128         prec = (rparecord_t *)r_array_slot(records, rec);
129         if (prec->type & RPA_RECORD_START) {
130                 if ((rec = rpa_recordtree_get(records, rec, RPA_RECORD_END)) < 0)
131                         return -1;
132         }
133         if (++rec >= r_array_length(records))
134                 return -1;
135         prec = (rparecord_t *)r_array_slot(records, rec);
136         if (prec->type & RPA_RECORD_START)
137                 return rpa_recordtree_get(records, rec, type);
138         return -1;
139 }
140
141
142 long rpa_recordtree_prev(rarray_t *records, long rec, unsigned long type)
143 {
144         rparecord_t *prec;
145
146         if (rec < 0 || rec >= r_array_length(records))
147                 return -1;
148         prec = (rparecord_t *)r_array_slot(records, rec);
149         if (prec->type & RPA_RECORD_END) {
150                 if ((rec = rpa_recordtree_get(records, rec, RPA_RECORD_START)) < 0)
151                         return -1;
152         }
153         if (--rec < 0)
154                 return -1;
155         prec = (rparecord_t *)r_array_slot(records, rec);
156         if (prec->type & RPA_RECORD_END)
157                 return rpa_recordtree_get(records, rec, type);
158         return -1;
159 }
160
161
162 long rpa_recordtree_parent(rarray_t *records, long rec, unsigned long type)
163 {
164         long last = -1, parent = -1;
165
166         if (rec < 0 || rec >= r_array_length(records))
167                 return -1;
168         for ( ;rec >= 0; rec = rpa_recordtree_next(records, last, RPA_RECORD_END)) {
169                 last = rpa_recordtree_get(records, rec, RPA_RECORD_END);
170         }
171         parent = last + 1;
172         if (parent >= r_array_length(records))
173                 return -1;
174         return rpa_recordtree_get(records, parent, type);
175 }
176
177
178 long rpa_recordtree_size(rarray_t *records, long rec)
179 {
180         long first = rpa_recordtree_get(records, rec, RPA_RECORD_START);
181         long last = rpa_recordtree_get(records, rec, RPA_RECORD_END);
182         if (first < 0 || last < 0)
183                 return -1;
184         return (last - first + 1);
185 }
186
187
188 long rpa_recordtree_copy(rarray_t *dst, rarray_t *src, long rec)
189 {
190         rparecord_t *prec;
191         long size, i;
192         rec = rpa_recordtree_get(src, rec, RPA_RECORD_START);
193         size = rpa_recordtree_size(src, rec);
194
195         for (i = 0; i < size; i++) {
196                 prec = rpa_record_get(src, i);
197                 r_array_add(dst, prec);
198         }
199         return size;
200 }
201
202
203 long rpa_recordtree_walk(rarray_t *records, long rec, long level, rpa_recordtree_callback callback, rpointer userdata)
204 {
205         long child;
206
207         if (level > 128)
208                 return -1;
209         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
210         if (callback && callback(records, rec, userdata) < 0)
211                 return -1;
212         for (child = rpa_recordtree_firstchild(records, rec, RPA_RECORD_START); child >= 0; child = rpa_recordtree_next(records, child, RPA_RECORD_START)) {
213                 if (rpa_recordtree_walk(records, child, level + 1, callback, userdata) < 0)
214                         return -1;
215         }
216         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
217         if (callback && callback(records, rec, userdata) < 0)
218                 return -1;
219         return 0;
220 }
221
222
223 static void rpa_recordptr_setusertype(rparecord_t *prec, ruint32 usertype, rvalset_t op)
224 {
225         switch (op) {
226         case RVALSET_OR:
227                 prec->usertype |= usertype;
228                 break;
229         case RVALSET_XOR:
230                 prec->usertype ^= usertype;
231                 break;
232         case RVALSET_AND:
233                 prec->usertype &= usertype;
234                 break;
235         default:
236                 prec->usertype = usertype;
237         }
238 }
239
240
241 long rpa_record_getruleuid(rarray_t *records, long rec)
242 {
243         rparecord_t *prec;
244
245         if (rec < 0)
246                 return -1;
247         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
248         if (rec >= r_array_length(records))
249                 return -1;
250         prec = (rparecord_t *)r_array_slot(records, rec);
251         return prec->ruleuid;
252 }
253
254
255 void rpa_record_setusertype(rarray_t *records, long rec, ruint32 usertype, rvalset_t op)
256 {
257         rparecord_t *prec;
258
259         if (rec < 0)
260                 return;
261         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
262         if (rec >= r_array_length(records))
263                 return;
264         prec = (rparecord_t *)r_array_slot(records, rec);
265         rpa_recordptr_setusertype(prec, usertype, op);
266         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
267         if (rec >= r_array_length(records))
268                 return;
269         prec = (rparecord_t *)r_array_slot(records, rec);
270         rpa_recordptr_setusertype(prec, usertype, op);
271 }
272
273
274 long rpa_record_getusertype(rarray_t *records, long rec)
275 {
276         rparecord_t *prec;
277
278         if (rec < 0)
279                 return -1;
280         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
281         if (rec >= r_array_length(records))
282                 return -1;
283         prec = (rparecord_t *)r_array_slot(records, rec);
284         return prec->usertype;
285 }
286
287
288 int rpa_record_optchar(rparecord_t *prec, int defc)
289 {
290         int optc = defc;
291
292         if ((prec->usertype & RPA_MATCH_MASK) == RPA_MATCH_OPTIONAL)
293                 optc = '?';
294         else if ((prec->usertype & RPA_MATCH_MASK) == RPA_MATCH_MULTIPLE)
295                 optc = '+';
296         else if ((prec->usertype & RPA_MATCH_MASK) == RPA_MATCH_MULTIOPT)
297                 optc = '*';
298         else
299                 optc = defc;
300         return optc;
301 }
302
303
304 int rpa_record_loopchar(rparecord_t *prec, int defc)
305 {
306         int loopc = defc;
307
308         if ((prec->usertype & RPA_LOOP_PATH) && (prec->usertype & RPA_NONLOOP_PATH)) {
309                 /*
310                  * This is an error, should never happen
311                  */
312                 loopc = 'R';
313         } else if ((prec->usertype & RPA_LOOP_PATH)) {
314                 loopc = 'L';
315         } else if ((prec->usertype & RPA_NONLOOP_PATH)) {
316                 loopc = 'N';
317         } else {
318                 loopc = defc;
319         }
320         return loopc;
321 }
322
323
324 void rpa_record_dump(rarray_t *records, long rec)
325 {
326         rparecord_t *prec;
327         long start, end, first, last, next, prev, parent;
328         char buf[240];
329         int bufsize = sizeof(buf) - 1;
330         int n = 0, size;
331         char optc = ' ';
332
333         if (rec < 0 || rec >= r_array_length(records))
334                 return;
335         prec = (rparecord_t *)r_array_slot(records, rec);
336         if (prec->type & RPA_RECORD_END) {
337                 if ((prec->usertype & RPA_MATCH_MASK) == RPA_MATCH_OPTIONAL)
338                         optc = '?';
339                 else if ((prec->usertype & RPA_MATCH_MASK) == RPA_MATCH_MULTIPLE)
340                         optc = '+';
341                 else if ((prec->usertype & RPA_MATCH_MASK) == RPA_MATCH_MULTIOPT)
342                         optc = '*';
343         }
344
345         r_memset(buf, 0, bufsize);
346
347         start = rpa_recordtree_get(records, rec, RPA_RECORD_START);
348         end = rpa_recordtree_get(records, rec, RPA_RECORD_END);
349         first = rpa_recordtree_firstchild(records, rec, RPA_RECORD_START);
350         last = rpa_recordtree_lastchild(records, rec, RPA_RECORD_START);
351         next = rpa_recordtree_next(records, rec, RPA_RECORD_START);
352         prev = rpa_recordtree_prev(records, rec, RPA_RECORD_START);
353         parent = rpa_recordtree_parent(records, rec, RPA_RECORD_START);
354
355         n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, "%5ld: [ s: %5ld, e: %5ld, p: %5ld ] ( %4d, 0x%03x ) : ", rec, start, end, parent, prec->ruleuid, prec->usertype);
356         if (prec->type & RPA_RECORD_START)
357                 n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, "START ");
358         if (prec->type & RPA_RECORD_END)
359                 n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, "END   ");
360         n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, "%s ", prec->rule);
361
362         r_memset(buf + n, ' ', bufsize - n);
363         n = 90;
364         n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, " %5d, %4d", prec->top, prec->size);
365
366 #if 0
367         r_memset(buf + n, ' ', bufsize - n);
368         n = 105;
369         n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, "[ 0x%016lx ]", prec->userdata);
370 #endif
371         r_memset(buf + n, ' ', bufsize - n);
372         n = 130;
373         n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, " %c %c %c", optc,
374                         (prec->usertype & RPA_LOOP_PATH) ? 'L' : ' ', (prec->usertype & RPA_NONLOOP_PATH) ? 'N' : ' ');
375         n += r_snprintf(buf + n, n < bufsize ? bufsize - n : 0, " : ");
376         size = prec->inputsiz;
377         if (size >= bufsize - n - 1)
378                 size = bufsize - n - 1;
379         if (prec->type & RPA_RECORD_END) {
380                 r_strncpy(buf + n, prec->input, size);
381                 n += size;
382                 buf[n] = '\0';
383         }
384
385         r_printf("%s\n", buf);
386 }
387
388
389 void rpa_record_dumpindented(rarray_t *records, long rec, int level)
390 {
391         char buffer[1024];
392         rparecord_t *prec;
393         int i, size;
394
395         if (rec < 0 || rec >= r_array_length(records))
396                 return;
397         r_memset(buffer, 0, sizeof(buffer));
398         prec = (rparecord_t *)r_array_slot(records, rec);
399         for (i = 0; i < level; i++)
400                 r_printf("   ");
401         r_printf("   ");
402         r_printf("(");
403         r_printf("%s, %c, %c", prec->rule, rpa_record_optchar(prec, 'x'), rpa_record_loopchar(prec, 'x'));
404         r_printf(")");
405         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
406         prec = (rparecord_t *)r_array_slot(records, rec);
407         size = R_MIN(prec->inputsiz, sizeof(buffer) - 1);
408         r_strncpy(buffer, prec->input, size);
409
410         if (size == (sizeof(buffer) - 1))
411                 r_printf(" %s ...\n", buffer);
412         else
413                 r_printf(" %s\n", buffer);
414         return;
415 }
416
417
418 rarray_t *rpa_records_create()
419 {
420         rarray_t *records;
421
422         records = r_array_create(sizeof(rparecord_t));
423         return records;
424 }
425
426 void rpa_records_destroy(rarray_t *records)
427 {
428         r_array_destroy(records);
429 }
430
431
432 long rpa_records_length(rarray_t *records)
433 {
434         return r_array_length(records);
435 }
436
437
438 rparecord_t *rpa_records_slot(rarray_t *records, long index)
439 {
440         if (index < 0 || index >= r_array_length(records))
441                 return NULL;
442         return (rparecord_t *)r_array_slot(records, index);
443 }