~ubuntu-branches/ubuntu/quantal/libee/quantal

« back to all changes in this revision

Viewing changes to src/primitivetype.c

  • Committer: Bazaar Package Importer
  • Author(s): Pierre Chifflier
  • Date: 2010-12-11 12:37:09 UTC
  • Revision ID: james.westby@ubuntu.com-20101211123709-i8v7mpdtzhgjoqn5
Tags: upstream-0.1.0
ImportĀ upstreamĀ versionĀ 0.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @file primitivetype.c
 
3
 * Implementation of the primitiveType class.
 
4
 *//*
 
5
 * Libee - An Event Expression Library inspired by CEE
 
6
 * Copyright 2010 by Rainer Gerhards and Adiscon GmbH.
 
7
 *
 
8
 * This file is part of libee.
 
9
 *
 
10
 * This library is free software; you can redistribute it and/or
 
11
 * modify it under the terms of the GNU Lesser General Public
 
12
 * License as published by the Free Software Foundation; either
 
13
 * version 2.1 of the License, or (at your option) any later version.
 
14
 *
 
15
 * This library is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
 * Lesser General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU Lesser General Public
 
21
 * License along with this library; if not, write to the Free Software
 
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
23
 *
 
24
 * A copy of the LGPL v2.1 can be found in the file "COPYING" in this distribution.
 
25
 */
 
26
#include "config.h"
 
27
#include <stdlib.h>
 
28
#include <stdio.h>
 
29
#include <stdarg.h>
 
30
#include <assert.h>
 
31
#include <ctype.h>
 
32
 
 
33
#include "libee/libee.h"
 
34
#include "libee/internal.h"
 
35
 
 
36
#define ERR_ABORT {r = 1; goto done; }
 
37
 
 
38
#define CHECK_CTX \
 
39
        if(ctx->objID != ObjID_CTX) { \
 
40
                r = -1; \
 
41
                goto done; \
 
42
        }
 
43
 
 
44
ee_ctx
 
45
ee_initPrimitiveType(void)
 
46
{
 
47
        ee_ctx ctx;
 
48
        if((ctx = calloc(1, sizeof(struct ee_ctx_s))) == NULL)
 
49
                goto done;
 
50
 
 
51
        ctx->objID = ObjID_CTX;
 
52
        ctx->dbgCB = NULL;
 
53
done:
 
54
        return ctx;
 
55
}
 
56
 
 
57
int
 
58
ee_exitPrimitiveType(ee_ctx ctx)
 
59
{
 
60
        int r = 0;
 
61
 
 
62
        CHECK_CTX;
 
63
 
 
64
        ctx->objID = ObjID_None; /* prevent double free */
 
65
        free(ctx);
 
66
done:
 
67
        return r;
 
68
}
 
69
 
 
70
/* some helpers */
 
71
static inline int
 
72
hParseInt(unsigned char **buf, es_size_t *lenBuf)
 
73
{
 
74
        unsigned char *p = *buf;
 
75
        es_size_t len = *lenBuf;
 
76
        int i = 0;
 
77
        
 
78
        while(len > 0 && isdigit(*p)) {
 
79
                i = i * 10 + *p - '0';
 
80
                ++p;
 
81
                --len;
 
82
        }
 
83
 
 
84
        *buf = p;
 
85
        *lenBuf = len;
 
86
        return i;
 
87
}
 
88
 
 
89
/* parsers for the primitive types
 
90
 *
 
91
 * All parsers receive 
 
92
 *
 
93
 * @param[in] ctx context object
 
94
 * @param[in] str the to-be-parsed string
 
95
 * @param[in/out] offs an offset into the string
 
96
 * @param[in] ed string with extra data for parser use
 
97
 * @param[out] newVal newly created value
 
98
 *
 
99
 * They will try to parse out "their" object from the string. If they
 
100
 * succeed, they:
 
101
 *
 
102
 * create a nw ee_value (newVal) and store the obtained value into it
 
103
 * update buf and lenBuf to reflect the parsing carried out
 
104
 *
 
105
 * returns 0 on success and EE_WRONGPARSER if this parser could
 
106
 *           not successfully parse (but all went well otherwise) and something
 
107
 *           else in case of an error.
 
108
 */
 
109
#define BEGINParser(ParserName) \
 
110
int ee_parse##ParserName(ee_ctx __attribute__((unused)) ctx, es_str_t *str, es_size_t *offs, \
 
111
                      __attribute__((unused)) es_str_t *ed, struct ee_value **value) \
 
112
{ \
 
113
        es_size_t r = EE_WRONGPARSER;
 
114
 
 
115
#define ENDParser \
 
116
        return r; \
 
117
}
 
118
 
 
119
 
 
120
/**
 
121
 * Parse a RFC3164 Date.
 
122
 */
 
123
BEGINParser(RFC3164Date)
 
124
        unsigned char *p;
 
125
        es_size_t len, orglen;
 
126
        /* variables to temporarily hold time information while we parse */
 
127
        int month;
 
128
        int day;
 
129
        //int year = 0; /* 0 means no year provided */
 
130
        int hour; /* 24 hour clock */
 
131
        int minute;
 
132
        int second;
 
133
 
 
134
        assert(*offs < es_strlen(str));
 
135
 
 
136
        p = es_getBufAddr(str) + *offs;
 
137
        orglen = len = es_strlen(str) - *offs;
 
138
        /* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec),
 
139
         * we may see the following character sequences occur:
 
140
         *
 
141
         * J(an/u(n/l)), Feb, Ma(r/y), A(pr/ug), Sep, Oct, Nov, Dec
 
142
         *
 
143
         * We will use this for parsing, as it probably is the
 
144
         * fastest way to parse it.
 
145
         */
 
146
        if(len < 3)
 
147
                goto fail;
 
148
 
 
149
        switch(*p++)
 
150
        {
 
151
        case 'j':
 
152
        case 'J':
 
153
                if(*p == 'a' || *p == 'A') {
 
154
                        ++p;
 
155
                        if(*p == 'n' || *p == 'N') {
 
156
                                ++p;
 
157
                                month = 1;
 
158
                        } else
 
159
                                goto fail;
 
160
                } else if(*p == 'u' || *p == 'U') {
 
161
                        ++p;
 
162
                        if(*p == 'n' || *p == 'N') {
 
163
                                ++p;
 
164
                                month = 6;
 
165
                        } else if(*p == 'l' || *p == 'L') {
 
166
                                ++p;
 
167
                                month = 7;
 
168
                        } else
 
169
                                goto fail;
 
170
                } else
 
171
                        goto fail;
 
172
                break;
 
173
        case 'f':
 
174
        case 'F':
 
175
                if(*p == 'e' || *p == 'E') {
 
176
                        ++p;
 
177
                        if(*p == 'b' || *p == 'B') {
 
178
                                ++p;
 
179
                                month = 2;
 
180
                        } else
 
181
                                goto fail;
 
182
                } else
 
183
                        goto fail;
 
184
                break;
 
185
        case 'm':
 
186
        case 'M':
 
187
                if(*p == 'a' || *p == 'A') {
 
188
                        ++p;
 
189
                        if(*p == 'r' || *p == 'R') {
 
190
                                ++p;
 
191
                                month = 3;
 
192
                        } else if(*p == 'y' || *p == 'Y') {
 
193
                                ++p;
 
194
                                month = 5;
 
195
                        } else
 
196
                                goto fail;
 
197
                } else
 
198
                        goto fail;
 
199
                break;
 
200
        case 'a':
 
201
        case 'A':
 
202
                if(*p == 'p' || *p == 'P') {
 
203
                        ++p;
 
204
                        if(*p == 'r' || *p == 'R') {
 
205
                                ++p;
 
206
                                month = 4;
 
207
                        } else
 
208
                                goto fail;
 
209
                } else if(*p == 'u' || *p == 'U') {
 
210
                        ++p;
 
211
                        if(*p == 'g' || *p == 'G') {
 
212
                                ++p;
 
213
                                month = 8;
 
214
                        } else
 
215
                                goto fail;
 
216
                } else
 
217
                        goto fail;
 
218
                break;
 
219
        case 's':
 
220
        case 'S':
 
221
                if(*p == 'e' || *p == 'E') {
 
222
                        ++p;
 
223
                        if(*p == 'p' || *p == 'P') {
 
224
                                ++p;
 
225
                                month = 9;
 
226
                        } else
 
227
                                goto fail;
 
228
                } else
 
229
                        goto fail;
 
230
                break;
 
231
        case 'o':
 
232
        case 'O':
 
233
                if(*p == 'c' || *p == 'C') {
 
234
                        ++p;
 
235
                        if(*p == 't' || *p == 'T') {
 
236
                                ++p;
 
237
                                month = 10;
 
238
                        } else
 
239
                                goto fail;
 
240
                } else
 
241
                        goto fail;
 
242
                break;
 
243
        case 'n':
 
244
        case 'N':
 
245
                if(*p == 'o' || *p == 'O') {
 
246
                        ++p;
 
247
                        if(*p == 'v' || *p == 'V') {
 
248
                                ++p;
 
249
                                month = 11;
 
250
                        } else
 
251
                                goto fail;
 
252
                } else
 
253
                        goto fail;
 
254
                break;
 
255
        case 'd':
 
256
        case 'D':
 
257
                if(*p == 'e' || *p == 'E') {
 
258
                        ++p;
 
259
                        if(*p == 'c' || *p == 'C') {
 
260
                                ++p;
 
261
                                month = 12;
 
262
                        } else
 
263
                                goto fail;
 
264
                } else
 
265
                        goto fail;
 
266
                break;
 
267
        default:
 
268
                goto fail;
 
269
        }
 
270
 
 
271
        len -= 3;
 
272
 
 
273
        /* done month */
 
274
 
 
275
        if(len == 0 || *p++ != ' ')
 
276
                goto fail;
 
277
        --len;
 
278
 
 
279
        /* we accept a slightly malformed timestamp when receiving. This is
 
280
         * we accept one-digit days
 
281
         */
 
282
        if(*p == ' ') {
 
283
                --len;
 
284
                ++p;
 
285
        }
 
286
 
 
287
        day = hParseInt(&p, &len);
 
288
        if(day < 1 || day > 31)
 
289
                goto fail;
 
290
 
 
291
        if(len == 0 || *p++ != ' ')
 
292
                goto fail;
 
293
        --len;
 
294
 
 
295
        /* time part */
 
296
        hour = hParseInt(&p, &len);
 
297
        if(hour > 1970 && hour < 2100) {
 
298
                /* if so, we assume this actually is a year. This is a format found
 
299
                 * e.g. in Cisco devices.
 
300
                 *
 
301
                year = hour;
 
302
                */
 
303
 
 
304
                /* re-query the hour, this time it must be valid */
 
305
                if(len == 0 || *p++ != ' ')
 
306
                        goto fail;
 
307
                --len;
 
308
                hour = hParseInt(&p, &len);
 
309
        }
 
310
 
 
311
        if(hour < 0 || hour > 23)
 
312
                goto fail;
 
313
 
 
314
        if(len == 0 || *p++ != ':')
 
315
                goto fail;
 
316
        --len;
 
317
        minute = hParseInt(&p, &len);
 
318
        if(minute < 0 || minute > 59)
 
319
                goto fail;
 
320
 
 
321
        if(len == 0 || *p++ != ':')
 
322
                goto fail;
 
323
        --len;
 
324
        second = hParseInt(&p, &len);
 
325
        if(second < 0 || second > 60)
 
326
                goto fail;
 
327
 
 
328
        /* we provide support for an extra ":" after the date. While this is an
 
329
         * invalid format, it occurs frequently enough (e.g. with Cisco devices)
 
330
         * to permit it as a valid case. -- rgerhards, 2008-09-12
 
331
         */
 
332
        if(len > 0 && *p == ':') {
 
333
                ++p; /* just skip past it */
 
334
                --len;
 
335
        }
 
336
 
 
337
        /* we had success, so update parse pointer and caller-provided timestamp
 
338
         * fields we do not have are not updated in the caller's timestamp. This
 
339
         * is the reason why the caller must pass in a correct timestamp.
 
340
         */
 
341
        es_size_t usedLen =  orglen - len;
 
342
        es_str_t *valstr = es_newStrFromSubStr(str, *offs, usedLen);
 
343
        *value = ee_newValue(ctx);
 
344
        ee_setStrValue(*value, valstr);
 
345
        *offs += usedLen;
 
346
        r = 0; /* parsing was successful */
 
347
#if 0 /* TODO: see how we represent the actual timestamp */
 
348
        pTime->month = month;
 
349
        if(year > 0)
 
350
                pTime->year = year; /* persist year if detected */
 
351
        pTime->day = day;
 
352
        pTime->hour = hour;
 
353
        pTime->minute = minute;
 
354
        pTime->second = second;
 
355
#endif
 
356
fail:
 
357
ENDParser
 
358
 
 
359
 
 
360
/**
 
361
 * Parse a Number.
 
362
 * Note that a number is an abstracted concept. We always represent it
 
363
 * as 64 bits (but may later change our mind if performance dictates so).
 
364
 */
 
365
BEGINParser(Number)
 
366
        unsigned char *p;
 
367
        es_size_t len, orglen;
 
368
        long long n;
 
369
 
 
370
 
 
371
//printf("parseNumber got '%s'\n", es_str2cstr(str, NULL)+ *offs);
 
372
        p = es_getBufAddr(str) + *offs;
 
373
        orglen = len = es_strlen(str) - *offs;
 
374
 
 
375
        n = hParseInt(&p, &len);
 
376
        if(p == es_getBufAddr(str))
 
377
                goto fail;
 
378
 
 
379
        if((*value = ee_newValue(ctx)) == NULL) {
 
380
                r = EE_NOMEM;
 
381
                goto fail;
 
382
        }
 
383
 
 
384
        /* success, persist */
 
385
        es_size_t usedLen =  orglen - len;
 
386
        es_str_t *valstr = es_newStrFromSubStr(str, *offs, usedLen);
 
387
        ee_setStrValue(*value, valstr);
 
388
        *offs += usedLen;
 
389
        r = 0;
 
390
fail:
 
391
ENDParser
 
392
 
 
393
 
 
394
/**
 
395
 * Parse a word.
 
396
 * A word is a SP-delimited entity. The parser always works, except if
 
397
 * the offset is position on a space upon entry.
 
398
 */
 
399
BEGINParser(Word)
 
400
        unsigned char *c;
 
401
        es_size_t i;
 
402
        es_size_t len;  /**< length of substring we finally extract */
 
403
        es_str_t *valstr;
 
404
 
 
405
        assert(str != NULL);
 
406
        assert(offs != NULL);
 
407
        c = es_getBufAddr(str);
 
408
        i = *offs;
 
409
 
 
410
        /* search end of word */
 
411
        while(i < es_strlen(str) && c[i] != ' ') 
 
412
                i++;
 
413
 
 
414
        if(i == *offs) {
 
415
                r = EE_WRONGPARSER;
 
416
                goto done;
 
417
        }
 
418
 
 
419
        /* success, persist */
 
420
        len =  i - *offs;
 
421
        CHKN(*value = ee_newValue(ctx));
 
422
        CHKN(valstr = es_newStrFromSubStr(str, *offs, len));
 
423
        ee_setStrValue(*value, valstr);
 
424
        *offs = i;
 
425
        r = 0;
 
426
 
 
427
done:   return r;
 
428
ENDParser
 
429
 
 
430
 
 
431
/**
 
432
 * Parse everything up to a specific character.
 
433
 * The character must be the only char inside extra data passed to the parser.
 
434
 * It is a program error if strlen(ed) != 1. It is considered a format error if
 
435
 * a) the to-be-parsed buffer is already positioned on the terminator character
 
436
 * b) there is no terminator until the end of the buffer
 
437
 * In those cases, the parsers declares itself as not being successful, in all
 
438
 * other cases a string is extracted.
 
439
 */
 
440
BEGINParser(CharTo)
 
441
        unsigned char *c;
 
442
        unsigned char cTerm;
 
443
        es_size_t i;
 
444
        es_str_t *valstr;
 
445
 
 
446
        assert(str != NULL);
 
447
        assert(offs != NULL);
 
448
        assert(es_strlen(ed) == 1);
 
449
        cTerm = *(es_getBufAddr(ed));
 
450
        c = es_getBufAddr(str);
 
451
        i = *offs;
 
452
 
 
453
        /* search end of word */
 
454
        while(i < es_strlen(str) && c[i] != cTerm) 
 
455
                i++;
 
456
 
 
457
        if(i == *offs || i == es_strlen(str) || c[i] != cTerm) {
 
458
                r = EE_WRONGPARSER;
 
459
                goto done;
 
460
        }
 
461
 
 
462
        /* success, persist */
 
463
        CHKN(*value = ee_newValue(ctx));
 
464
        CHKN(valstr = es_newStrFromSubStr(str, *offs, i - *offs));
 
465
        ee_setStrValue(*value, valstr);
 
466
        *offs = i;
 
467
        r = 0;
 
468
 
 
469
done:   return r;
 
470
ENDParser
 
471
 
 
472
 
 
473
 
 
474
/* helper to IPv4 address parser, checks the next set of numbers.
 
475
 * Syntax 1 to 3 digits, value together not larger than 255.
 
476
 * @param[in] str parse buffer
 
477
 * @param[in/out] offs offset into buffer, updated if successful
 
478
 * @return 0 if OK, 1 otherwise
 
479
 */
 
480
static int
 
481
chkIPv4AddrByte(es_str_t *str, es_size_t *offs)
 
482
{
 
483
        int val = 0;
 
484
        int r = 1;      /* default: fail -- simplifies things */
 
485
        unsigned char *c = es_getBufAddr(str);
 
486
        es_size_t i = *offs;
 
487
 
 
488
        if(i == es_strlen(str) || !isdigit(c[i])) goto done;
 
489
        val = c[i++] - '0';
 
490
        if(i < es_strlen(str) && isdigit(c[i])) {
 
491
                val = val * 10 + c[i++] - '0';
 
492
                if(i < es_strlen(str) && isdigit(c[i]))
 
493
                        val = val * 10 + c[i++] - '0';
 
494
        }
 
495
        if(val > 255)   /* cannot be a valid IP address byte! */
 
496
                goto done;
 
497
 
 
498
        *offs = i;
 
499
        r = 0;
 
500
 
 
501
done:   return r;
 
502
}
 
503
/**
 
504
 * Parser for IPv4 addresses.
 
505
 */
 
506
BEGINParser(IPv4)
 
507
        unsigned char *c;
 
508
        es_size_t i;
 
509
        es_str_t *valstr;
 
510
 
 
511
        assert(str != NULL);
 
512
        assert(offs != NULL);
 
513
        i = *offs;
 
514
        if(es_strlen(str) - i + 1 < 7) {
 
515
                /* IPv4 addr requires at least 7 characters */
 
516
                r = EE_WRONGPARSER;
 
517
                goto done;
 
518
        }
 
519
        c = es_getBufAddr(str);
 
520
 
 
521
        r = EE_WRONGPARSER; /* let's assume things go wrong, leads to simpler code */
 
522
        /* byte 1*/
 
523
        if(chkIPv4AddrByte(str, &i) != 0) goto done;
 
524
        if(i == es_strlen(str) || c[i++] != '.') goto done;
 
525
        /* byte 2*/
 
526
        if(chkIPv4AddrByte(str, &i) != 0) goto done;
 
527
        if(i == es_strlen(str) || c[i++] != '.') goto done;
 
528
        /* byte 3*/
 
529
        if(chkIPv4AddrByte(str, &i) != 0) goto done;
 
530
        if(i == es_strlen(str) || c[i++] != '.') goto done;
 
531
        /* byte 4 - we do NOT need any char behind it! */
 
532
        if(chkIPv4AddrByte(str, &i) != 0) goto done;
 
533
 
 
534
        /* if we reach this point, we found a valid IP address */
 
535
        CHKN(*value = ee_newValue(ctx));
 
536
        CHKN(valstr = es_newStrFromSubStr(str, *offs, i - *offs));
 
537
        ee_setStrValue(*value, valstr);
 
538
        *offs = i;
 
539
        r = 0;
 
540
 
 
541
done:   return r;
 
542
ENDParser