2
* @file primitivetype.c
3
* Implementation of the primitiveType class.
5
* Libee - An Event Expression Library inspired by CEE
6
* Copyright 2010 by Rainer Gerhards and Adiscon GmbH.
8
* This file is part of libee.
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.
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.
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
24
* A copy of the LGPL v2.1 can be found in the file "COPYING" in this distribution.
33
#include "libee/libee.h"
34
#include "libee/internal.h"
36
#define ERR_ABORT {r = 1; goto done; }
39
if(ctx->objID != ObjID_CTX) { \
45
ee_initPrimitiveType(void)
48
if((ctx = calloc(1, sizeof(struct ee_ctx_s))) == NULL)
51
ctx->objID = ObjID_CTX;
58
ee_exitPrimitiveType(ee_ctx ctx)
64
ctx->objID = ObjID_None; /* prevent double free */
72
hParseInt(unsigned char **buf, es_size_t *lenBuf)
74
unsigned char *p = *buf;
75
es_size_t len = *lenBuf;
78
while(len > 0 && isdigit(*p)) {
79
i = i * 10 + *p - '0';
89
/* parsers for the primitive types
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
99
* They will try to parse out "their" object from the string. If they
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
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.
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) \
113
es_size_t r = EE_WRONGPARSER;
121
* Parse a RFC3164 Date.
123
BEGINParser(RFC3164Date)
125
es_size_t len, orglen;
126
/* variables to temporarily hold time information while we parse */
129
//int year = 0; /* 0 means no year provided */
130
int hour; /* 24 hour clock */
134
assert(*offs < es_strlen(str));
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:
141
* J(an/u(n/l)), Feb, Ma(r/y), A(pr/ug), Sep, Oct, Nov, Dec
143
* We will use this for parsing, as it probably is the
144
* fastest way to parse it.
153
if(*p == 'a' || *p == 'A') {
155
if(*p == 'n' || *p == 'N') {
160
} else if(*p == 'u' || *p == 'U') {
162
if(*p == 'n' || *p == 'N') {
165
} else if(*p == 'l' || *p == 'L') {
175
if(*p == 'e' || *p == 'E') {
177
if(*p == 'b' || *p == 'B') {
187
if(*p == 'a' || *p == 'A') {
189
if(*p == 'r' || *p == 'R') {
192
} else if(*p == 'y' || *p == 'Y') {
202
if(*p == 'p' || *p == 'P') {
204
if(*p == 'r' || *p == 'R') {
209
} else if(*p == 'u' || *p == 'U') {
211
if(*p == 'g' || *p == 'G') {
221
if(*p == 'e' || *p == 'E') {
223
if(*p == 'p' || *p == 'P') {
233
if(*p == 'c' || *p == 'C') {
235
if(*p == 't' || *p == 'T') {
245
if(*p == 'o' || *p == 'O') {
247
if(*p == 'v' || *p == 'V') {
257
if(*p == 'e' || *p == 'E') {
259
if(*p == 'c' || *p == 'C') {
275
if(len == 0 || *p++ != ' ')
279
/* we accept a slightly malformed timestamp when receiving. This is
280
* we accept one-digit days
287
day = hParseInt(&p, &len);
288
if(day < 1 || day > 31)
291
if(len == 0 || *p++ != ' ')
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.
304
/* re-query the hour, this time it must be valid */
305
if(len == 0 || *p++ != ' ')
308
hour = hParseInt(&p, &len);
311
if(hour < 0 || hour > 23)
314
if(len == 0 || *p++ != ':')
317
minute = hParseInt(&p, &len);
318
if(minute < 0 || minute > 59)
321
if(len == 0 || *p++ != ':')
324
second = hParseInt(&p, &len);
325
if(second < 0 || second > 60)
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
332
if(len > 0 && *p == ':') {
333
++p; /* just skip past it */
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.
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);
346
r = 0; /* parsing was successful */
347
#if 0 /* TODO: see how we represent the actual timestamp */
348
pTime->month = month;
350
pTime->year = year; /* persist year if detected */
353
pTime->minute = minute;
354
pTime->second = second;
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).
367
es_size_t len, orglen;
371
//printf("parseNumber got '%s'\n", es_str2cstr(str, NULL)+ *offs);
372
p = es_getBufAddr(str) + *offs;
373
orglen = len = es_strlen(str) - *offs;
375
n = hParseInt(&p, &len);
376
if(p == es_getBufAddr(str))
379
if((*value = ee_newValue(ctx)) == NULL) {
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);
396
* A word is a SP-delimited entity. The parser always works, except if
397
* the offset is position on a space upon entry.
402
es_size_t len; /**< length of substring we finally extract */
406
assert(offs != NULL);
407
c = es_getBufAddr(str);
410
/* search end of word */
411
while(i < es_strlen(str) && c[i] != ' ')
419
/* success, persist */
421
CHKN(*value = ee_newValue(ctx));
422
CHKN(valstr = es_newStrFromSubStr(str, *offs, len));
423
ee_setStrValue(*value, valstr);
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.
447
assert(offs != NULL);
448
assert(es_strlen(ed) == 1);
449
cTerm = *(es_getBufAddr(ed));
450
c = es_getBufAddr(str);
453
/* search end of word */
454
while(i < es_strlen(str) && c[i] != cTerm)
457
if(i == *offs || i == es_strlen(str) || c[i] != cTerm) {
462
/* success, persist */
463
CHKN(*value = ee_newValue(ctx));
464
CHKN(valstr = es_newStrFromSubStr(str, *offs, i - *offs));
465
ee_setStrValue(*value, valstr);
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
481
chkIPv4AddrByte(es_str_t *str, es_size_t *offs)
484
int r = 1; /* default: fail -- simplifies things */
485
unsigned char *c = es_getBufAddr(str);
488
if(i == es_strlen(str) || !isdigit(c[i])) goto done;
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';
495
if(val > 255) /* cannot be a valid IP address byte! */
504
* Parser for IPv4 addresses.
512
assert(offs != NULL);
514
if(es_strlen(str) - i + 1 < 7) {
515
/* IPv4 addr requires at least 7 characters */
519
c = es_getBufAddr(str);
521
r = EE_WRONGPARSER; /* let's assume things go wrong, leads to simpler code */
523
if(chkIPv4AddrByte(str, &i) != 0) goto done;
524
if(i == es_strlen(str) || c[i++] != '.') goto done;
526
if(chkIPv4AddrByte(str, &i) != 0) goto done;
527
if(i == es_strlen(str) || c[i++] != '.') goto done;
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;
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);