2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 #include "EOQualifier.h"
28 //#define USE_DESCRIPTION_FOR_AT 1
30 static int qDebug = 0;
31 static NSMutableDictionary *EOQualifierParserTypeMappings = nil;
34 The literals understood by the value parser.
36 NOTE: Any literal used here can never be used as a key ! So add as little
40 const unsigned char *token;
45 static EOQPTokEntry toks[] = {
55 static inline void _setupLiterals(void) {
56 static BOOL didSetup = NO;
59 toks[0].value = [[NSNull null] retain];
60 toks[1].value = toks[0].value;
61 toks[2].value = [[NSNumber numberWithBool:YES] retain];
62 toks[3].value = [[NSNumber numberWithBool:NO] retain];
63 toks[4].value = toks[2].value;
64 toks[5].value = toks[3].value;
68 static Class StringClass = Nil;
69 static Class NumberClass = Nil;
70 static EONull *null = nil;
72 /* parsing functions */
74 static EOQualifier *_parseCompoundQualifier(id _ctx, const char *_buf,
75 unsigned _bufLen, unsigned *_qualLen);
76 static EOQualifier *_testOperator(id _ctx, const char *_buf,
77 unsigned _bufLen, unsigned *_opLen,
79 static EOQualifier *_parseQualifiers(id _ctx, const char *_buf,
80 unsigned _bufLen, unsigned *_qualLen);
81 static EOQualifier *_parseParenthesisQualifier(id _ctx,
82 const char *_buf, unsigned _bufLen,
84 static EOQualifier *_parseNotQualifier(id _ctx, const char *_buf,
85 unsigned _bufLen, unsigned *_qualLen);
86 static EOQualifier *_parseKeyCompQualifier(id _ctx, const char *_buf,
87 unsigned _bufLen, unsigned *_qualLen);
88 static NSString *_parseKey(id _ctx, const char *_buf, unsigned _bufLen,
90 static id _parseValue(id _ctx, const char *_buf, unsigned _bufLen,
92 static inline unsigned _countWhiteSpaces(const char *_buf, unsigned _bufLen);
93 static NSString *_parseOp(const char *_buf, unsigned _bufLen,
96 @interface EOQualifierParserContext : NSObject
98 NSMapTable *qualifierCache;
100 - (NSDictionary *)resultForFunction:(NSString *)_fct atPos:(unsigned)_pos;
101 - (void)setResult:(NSDictionary *)_dict forFunction:(NSString *)_fct
102 atPos:(unsigned)_pos;
103 - (id)getObjectFromStackFor:(char)_c;
107 - (EOQualifier *)keyComparisonQualifierWithLeftKey:(NSString *)_leftKey
108 operatorSelector:(SEL)_sel
109 rightKey:(NSString *)_rightKey;
110 - (EOQualifier *)keyValueQualifierWithKey:(NSString *)_key
111 operatorSelector:(SEL)_sel
113 - (EOQualifier *)andQualifierWithArray:(NSArray *)_qualifiers;
114 - (EOQualifier *)orQualifierWithArray:(NSArray *)_qualifiers;
115 - (EOQualifier *)notQualifierWithQualifier:(EOQualifier *)_qualifier;
119 @interface EOQualifierVAParserContext : EOQualifierParserContext
123 + (id)contextWithVaList:(va_list *)_va;
124 - (id)initWithVaList:(va_list *)_va;
127 @interface EOQualifierEnumeratorParserContext : EOQualifierParserContext
129 NSEnumerator *enumerator;
131 + (id)contextWithEnumerator:(NSEnumerator *)_enumerator;
132 - (id)initWithEnumerator:(NSEnumerator *)_enumerator;
135 @implementation EOQualifierVAParserContext
137 + (id)contextWithVaList:(va_list *)_va {
138 return [[[EOQualifierVAParserContext alloc] initWithVaList:_va] autorelease];
141 - (id)initWithVaList:(va_list *)_va {
142 if ((self = [super init])) {
148 - (id)getObjectFromStackFor:(char)_c {
151 if (StringClass == Nil) StringClass = [NSString class];
152 if (NumberClass == Nil) NumberClass = [NSNumber class];
153 if (null == nil) null = [EONull null];
156 char *str = va_arg(*self->va, char*);
157 obj = [StringClass stringWithCString:str];
159 else if (_c == 'd') {
160 int i= va_arg(*self->va, int);
161 obj = [NumberClass numberWithInt:i];
163 else if (_c == 'f') {
164 double d = va_arg(*self->va, double);
165 obj = [NumberClass numberWithDouble:d];
167 else if (_c == '@') {
168 id o = va_arg(*self->va, id);
169 #if USE_DESCRIPTION_FOR_AT
170 obj = (o == nil) ? (id)null : (id)[o description];
172 obj = (o == nil) ? (id)null : (id)o;
176 [NSException raise:@"NSInvalidArgumentException"
177 format:@"unknown conversation char %c", _c];
182 @end /* EOQualifierVAParserContext */
184 @implementation EOQualifierEnumeratorParserContext
186 + (id)contextWithEnumerator:(NSEnumerator *)_enumerator {
187 return [[[EOQualifierEnumeratorParserContext alloc]
188 initWithEnumerator:_enumerator] autorelease];
191 - (id)initWithEnumerator:(NSEnumerator *)_enumerator {
192 if ((self = [super init])) {
193 ASSIGN(self->enumerator, _enumerator);
199 [self->enumerator release];
203 - (id)getObjectFromStackFor:(char)_c {
204 static Class NumberClass = Nil;
207 if (NumberClass == Nil) NumberClass = [NSNumber class];
209 o = [self->enumerator nextObject];
212 #if USE_DESCRIPTION_FOR_AT
213 return [o description];
219 return [NumberClass numberWithDouble:[o doubleValue]];
222 return [NumberClass numberWithInt:[o intValue]];
225 // return [NSString stringWithCString:[o cString]];
226 return [[o copy] autorelease];
229 [NSException raise:@"NSInvalidArgumentException"
230 format:@"unknown or not allowed conversation char %c", _c];
235 @end /* EOQualifierEnumeratorParserContext */
237 @implementation EOQualifierParserContext
240 if (StringClass == Nil) StringClass = [NSString class];
242 if ((self = [super init])) {
243 self->qualifierCache = NSCreateMapTable(NSObjectMapKeyCallBacks,
244 NSObjectMapValueCallBacks,
251 if (self->qualifierCache) NSFreeMapTable(self->qualifierCache);
255 - (NSDictionary *)resultForFunction:(NSString *)_fct atPos:(unsigned)_pos
257 return NSMapGet(self->qualifierCache,
258 [StringClass stringWithFormat:@"%@_%d", _fct, _pos]);
261 - (void)setResult:(NSDictionary *)_dict forFunction:(NSString *)_fct
264 NSMapInsert(self->qualifierCache,
265 [StringClass stringWithFormat:@"%@_%d", _fct, _pos],
269 - (id)getObjectFromStackFor:(char)_c {
270 [self doesNotRecognizeSelector:_cmd];
276 - (EOQualifier *)keyComparisonQualifierWithLeftKey:(NSString *)_leftKey
277 operatorSelector:(SEL)_sel
278 rightKey:(NSString *)_rightKey
280 static Class clazz = Nil;
281 if (clazz == Nil) clazz = [EOKeyComparisonQualifier class];
283 return [[[clazz alloc]
284 initWithLeftKey:_leftKey
285 operatorSelector:_sel
289 - (EOQualifier *)keyValueQualifierWithKey:(NSString *)_key
290 operatorSelector:(SEL)_sel
293 static Class clazz = Nil;
294 if (clazz == Nil) clazz = [EOKeyValueQualifier class];
296 return [[[clazz alloc]
298 operatorSelector:_sel
302 - (EOQualifier *)andQualifierWithArray:(NSArray *)_qualifiers {
303 static Class clazz = Nil;
304 if (clazz == Nil) clazz = [EOAndQualifier class];
306 return [[[clazz alloc] initWithQualifierArray:_qualifiers] autorelease];
308 - (EOQualifier *)orQualifierWithArray:(NSArray *)_qualifiers {
309 static Class clazz = Nil;
310 if (clazz == Nil) clazz = [EOOrQualifier class];
312 return [[[clazz alloc] initWithQualifierArray:_qualifiers] autorelease];
315 - (EOQualifier *)notQualifierWithQualifier:(EOQualifier *)_qualifier {
316 static Class clazz = Nil;
317 if (clazz == Nil) clazz = [EONotQualifier class];
319 return [[[clazz alloc] initWithQualifier:_qualifier] autorelease];
322 - (EOQualifierVariable *)variableWithKey:(NSString *)_key {
323 static Class clazz = Nil;
324 if (clazz == Nil) clazz = [EOQualifierVariable class];
326 return [clazz variableWithKey:_key];
329 @end /* EOQualifierParserContext */
331 @implementation EOQualifier(Parsing)
333 + (void)registerValueClass:(Class)_valueClass forTypeName:(NSString *)_type {
334 if (EOQualifierParserTypeMappings == nil)
335 EOQualifierParserTypeMappings = [[NSMutableDictionary alloc] init];
338 NSLog(@"ERROR(%s): got passed no type name!", __PRETTY_FUNCTION__);
341 if (_valueClass == nil) {
342 NSLog(@"ERROR(%s): got passed no value-class for type '%@'!",
343 __PRETTY_FUNCTION__, _type);
347 [EOQualifierParserTypeMappings setObject:_valueClass forKey:_type];
350 + (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat,... {
352 EOQualifier *qualifier;
359 if (StringClass == Nil) StringClass = [NSString class];
361 bufLen = [_qualifierFormat cStringLength];
362 cbuf = malloc(bufLen + 1);
363 [_qualifierFormat getCString:cbuf]; cbuf[bufLen] = '\0';
366 va_start(va, _qualifierFormat);
368 _parseQualifiers([EOQualifierVAParserContext contextWithVaList:&va],
369 buf, bufLen, &length);
372 if (qualifier != nil) { /* check whether the rest of the string is OK */
374 length += _countWhiteSpaces(buf + length, bufLen - length);
376 if (length < bufLen) {
377 NSLog(@"WARNING(%s): unexpected chars at the end of the "
378 @"string(class=%@,len=%i) '%@'",
380 [_qualifierFormat class],
381 [_qualifierFormat length], _qualifierFormat);
382 NSLog(@" buf-length: %i", bufLen);
383 NSLog(@" length: %i", length);
384 NSLog(@" char[length]: '%c' (%i) '%s'", buf[length], buf[length],
388 else if (length > bufLen) {
389 NSLog(@"WARNING(%s): length should never be longer than bufLen ?, "
390 @"internal parsing error !",
391 __PRETTY_FUNCTION__);
398 + (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat
399 arguments:(NSArray *)_arguments
401 EOQualifier *qual = nil;
403 const char *buf = NULL;
405 EOQualifierEnumeratorParserContext *ctx;
408 if (StringClass == Nil) StringClass = [NSString class];
410 ctx = [EOQualifierEnumeratorParserContext contextWithEnumerator:
411 [_arguments objectEnumerator]];
413 //NSLog(@"qclass: %@", [_qualifierFormat class]);
414 buf = [_qualifierFormat cString];
415 bufLen = [_qualifierFormat cStringLength];
416 qual = _parseQualifiers(ctx, buf, bufLen, &length);
418 if (qual != nil) { /* check whether the rest of the string is OK */
419 if (length < bufLen) {
420 length += _countWhiteSpaces(buf + length, bufLen - length);
422 if (length != bufLen) {
423 NSLog(@"WARNING(%s): unexpected chars at the end of the string '%@'",
424 __PRETTY_FUNCTION__, _qualifierFormat);
431 @end /* EOQualifier(Parsing) */
433 static EOQualifier *_parseSingleQualifier(id _ctx, const char *_buf,
437 EOQualifier *res = nil;
439 if ((res = _parseParenthesisQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
441 NSLog(@"_parseSingleQualifier return <%@> for <%s> ", res, _buf);
445 if ((res = _parseNotQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
447 NSLog(@"_parseSingleQualifier return <%@> for <%s> ", res, _buf);
451 if ((res = _parseKeyCompQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
453 NSLog(@"_parseSingleQualifier return <%@> for <%s> length %d",
454 res, _buf, *_qualLen);
461 static EOQualifier *_parseQualifiers(id _ctx, const char *_buf, unsigned _bufLen,
464 EOQualifier *res = nil;
467 if ((res = _parseCompoundQualifier(_ctx, _buf, _bufLen, _qualLen))) {
469 NSLog(@"_parseQualifiers return <%@> for <%s> ", res, _buf);
473 if ((res = _parseSingleQualifier(_ctx, _buf, _bufLen, _qualLen))) {
475 NSLog(@"_parseQualifiers return <%@> for <%s> ", res, _buf);
480 NSLog(@"_parseQualifiers return nil for <%s> ", _buf);
485 static EOQualifier *_parseParenthesisQualifier(id _ctx, const char *_buf,
490 unsigned qualLen = 0;
491 EOQualifier *qual = nil;
493 pos = _countWhiteSpaces(_buf, _bufLen);
495 if (_bufLen <= pos + 2) /* at least open and close parenthesis */ {
497 NSLog(@"1_parseParenthesisQualifier return nil for <%s> ", _buf);
501 if (_buf[pos] != '(') {
503 NSLog(@"2_parseParenthesisQualifier return nil for <%s> ", _buf);
508 if (!(qual = _parseQualifiers(_ctx, _buf + pos, _bufLen - pos,
511 NSLog(@"3_parseParenthesisQualifier return nil for <%s> ", _buf);
517 if (_bufLen <= pos) {
519 NSLog(@"4_parseParenthesisQualifier return nil for <%s> qual[%@] %@ bufLen %d "
520 @"pos %d", _buf, [qual class], qual, _bufLen, pos);
524 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
525 if (_buf[pos] != ')') {
527 NSLog(@"5_parseParenthesisQualifier return nil for <%s> [%s] ", _buf, _buf+pos);
532 NSLog(@"6_parseParenthesisQualifier return <%@> for <%s> ", qual, _buf);
534 *_qualLen = pos + 1; /* one step after the parenthesis */
538 static EOQualifier *_parseNotQualifier(id _ctx, const char *_buf,
539 unsigned _bufLen, unsigned *_qualLen)
541 unsigned pos, len = 0;
543 EOQualifier *qual = nil;
545 pos = _countWhiteSpaces(_buf, _bufLen);
547 if (_bufLen - pos < 4) { /* at least 3 chars for 'NOT' */
549 NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
556 if (!(((c0 == 'n') || (c0 == 'N')) &&
557 ((c1 == 'o') || (c1 == 'O')) &&
558 ((c2 == 't') || (c2 == 'T')))) {
560 NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
564 qual = _parseSingleQualifier(_ctx, _buf + pos, _bufLen - pos, &len);
567 NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
571 *_qualLen = pos +len;
573 NSLog(@"_parseNotQualifier return %@ for <%s> ", qual, _buf);
575 return [_ctx notQualifierWithQualifier:qual];
578 static EOQualifier *_parseKeyCompQualifier(id _ctx, const char *_buf,
579 unsigned _bufLen, unsigned *_qualLen)
583 NSString *value = nil;
584 EOQualifier *qual = nil;
585 NSDictionary *dict = nil;
589 BOOL valueIsKey = NO;
591 dict = [_ctx resultForFunction:@"parseKeyCompQualifier" atPos:(unsigned)_buf];
594 NSLog(@"_parseKeyCompQual return <%@> [cached] for <%s> ", dict, _buf);
596 *_qualLen = [[dict objectForKey:@"length"] unsignedIntValue];
597 return [dict objectForKey:@"object"];
599 pos = _countWhiteSpaces(_buf, _bufLen);
601 if ((key = _parseKey(_ctx , _buf + pos, _bufLen - pos, &length)) == nil) {
603 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
608 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
610 if (!(op = _parseOp(_buf + pos, _bufLen - pos, &length))) {
612 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
615 sel = [EOQualifier operatorSelectorForString:op];
617 NSLog(@"WARNING(%s): possible unknown operator <%@>", __PRETTY_FUNCTION__,
620 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
624 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
627 value = _parseValue(_ctx, _buf + pos, _bufLen - pos, &length);
629 value = _parseKey(_ctx, _buf + pos, _bufLen - pos, &length);
632 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
642 ? [_ctx keyComparisonQualifierWithLeftKey:key
645 : [_ctx keyValueQualifierWithKey:key
650 NSLog(@"_parseKeyCompQualifier return <%@> for <%s> ", qual, _buf);
653 id keys[2], values[2];
654 keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
655 keys[1] = @"object"; values[1] = qual;
657 [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
658 forFunction:@"parseKeyCompQualifier"
659 atPos:(unsigned)_buf];
665 static NSString *_parseOp(const char *_buf, unsigned _bufLen,
674 NSLog(@"_parseOp _bufLen == 0 --> return nil");
677 pos = _countWhiteSpaces(_buf, _bufLen);
678 if (_bufLen - pos > 1) {/* at least an operation and a value */
682 if (((c0 >= '<') && (c0 <= '>')) || (c0 == '!')) {
685 if ((c1 >= '<') && (c1 <= '>')) {
687 result = [StringClass stringWithCString:_buf + pos length:2];
689 NSLog(@"_parseOp return <%@> for <%s> ", result, _buf);
693 result = [StringClass stringWithCString:&c0 length:1];
695 NSLog(@"_parseOp return <%@> for <%s> ", result, _buf);
699 else { /* string designator operator */
700 unsigned opStart = pos;
701 while (pos < _bufLen) {
702 if (_buf[pos] == ' ')
706 if (pos >= _bufLen) {
707 NSLog(@"WARNING(%s): found end of string during operator parsing",
708 __PRETTY_FUNCTION__);
712 NSLog(@"%s: _parseOp return <%@> for <%s> ", __PRETTY_FUNCTION__,
713 [StringClass stringWithCString:_buf + opStart
714 length:pos - opStart], _buf);
718 return [StringClass stringWithCString:_buf + opStart length:pos - opStart];
722 NSLog(@"_parseOp return nil for <%s> ", _buf);
726 static NSString *_parseKey(id _ctx, const char *_buf, unsigned _bufLen,
730 NSDictionary *dict = nil;
732 unsigned startKey = 0;
736 if (qDebug) NSLog(@"%s: _bufLen == 0 --> return nil", __PRETTY_FUNCTION__);
739 dict = [_ctx resultForFunction:@"parseKey" atPos:(unsigned)_buf];
742 NSLog(@"%s: return <%@> [cached] for <%s> ", __PRETTY_FUNCTION__,
745 *_keyLen = [[dict objectForKey:@"length"] unsignedIntValue];
746 return [dict objectForKey:@"object"];
748 pos = _countWhiteSpaces(_buf, _bufLen);
753 if (_bufLen - pos < 2) {
755 NSLog(@"%s: [c==%%,bufLen-pos<2]: _parseValue return nil for <%s> ",
756 __PRETTY_FUNCTION__, _buf);
761 result = [_ctx getObjectFromStackFor:_buf[pos]];
765 /* '{' for namspaces */
766 register BOOL isQuotedKey = NO;
770 else if (!(((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
773 NSLog(@"%s: [c!=AZaz{]: _parseKey return nil for <%s> ",
774 __PRETTY_FUNCTION__, _buf);
780 while (pos < _bufLen) {
782 if (isQuotedKey && c == '"')
785 ((c == ' ') || (c == '<') || (c == '>') || (c == '=') || (c == '!') ||
786 c == ')' || c == '(')
792 result = [StringClass stringWithCString:(_buf + startKey + 1)
793 length:(pos - startKey - 2)];
796 result = [StringClass stringWithCString:(_buf + startKey)
797 length:(pos - startKey)];
802 NSLog(@"%s: return <%@> for <%s> ", __PRETTY_FUNCTION__, result, _buf);
805 id keys[2], values[2];
807 keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
808 keys[1] = @"object"; values[1] = result;
811 [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
812 forFunction:@"parseKey"
813 atPos:(unsigned)_buf];
819 static id _parseValue(id _ctx, const char *_buf, unsigned _bufLen,
822 NSString *cast = nil;
823 NSDictionary *dict = nil;
828 if (NumberClass == Nil) NumberClass = [NSNumber class];
829 if (null == nil) null = [[NSNull null] retain];
832 if (qDebug) NSLog(@"_parseValue _bufLen == 0 --> return nil");
836 dict = [_ctx resultForFunction:@"parseValue" atPos:(unsigned)_buf];
839 NSLog(@"_parseKeyCompQualifier return <%@> [cached] for <%s> ",
842 *_keyLen = [[dict objectForKey:@"length"] unsignedIntValue];
843 return [dict objectForKey:@"object"];
846 pos = _countWhiteSpaces(_buf, _bufLen);
849 if (c == '$') { /* found EOQualifierVariable */
850 unsigned startVar = 0;
855 while (pos < _bufLen) {
856 if ((_buf[pos] == ' ') || (_buf[pos] == ')'))
861 varKey = [StringClass stringWithCString:(_buf + startVar)
862 length:pos - startVar];
863 obj = [_ctx variableWithKey:varKey];
866 /* first, check for CAST */
867 BOOL parseComplexCast = NO;
869 if (c == 'c' && _bufLen > 14) {
870 if (strstr(_buf, "cast") == _buf && (isspace(_buf[4]) || _buf[4]=='(')) {
871 /* for example: cast("1970-01-01T00:00:00Z" as 'dateTime') [min 15 #]*/
872 pos += 4; /* skip 'cast' */
873 while (isspace(_buf[pos])) /* skip spaces */
875 if (_buf[pos] != '(') {
876 NSLog(@"WARNING(%s): got unexpected cast string: '%s'",
877 __PRETTY_FUNCTION__, _buf);
880 pos++; /* skip opening bracket '(' */
882 parseComplexCast = YES;
886 else if (c == '(') { /* starting with a cast */
887 /* for example: (NSCalendarDate)"1999-12-12" [min 5 chars] */
888 unsigned startCast = 0;
892 while (pos < _bufLen) {
893 if (_buf[pos] == ')')
898 if (pos >= _bufLen) {
899 NSLog(@"WARNING(%s): found end of string while reading a cast",
900 __PRETTY_FUNCTION__);
904 cast = [StringClass stringWithCString:(_buf + startCast)
905 length:(pos - 1 - startCast)];
907 NSLog(@"%s: got cast %@", __PRETTY_FUNCTION__, cast);
910 /* next, check for FORMAT SPECIFIER */
912 if (_bufLen - pos < 2) {
914 NSLog(@"_parseValue return nil for <%s> ", _buf);
919 obj = [_ctx getObjectFromStackFor:_buf[pos]];
923 /* next, check for A NUMBER */
924 else if (((c >= '0') && (c <= '9')) || (c == '-')) { /* got a number */
925 unsigned startNumber;
929 while (pos < _bufLen) {
931 if (!((c >= '0') && (c <= '9')))
935 obj = [NumberClass numberWithInt:atoi(_buf + startNumber)];
938 /* check for some text literals */
939 if ((obj == nil) && ((_bufLen - pos) > 1)) {
942 for (i = 0; i < 20 && (toks[i].token != NULL) && (obj == nil); i++) {
943 const unsigned char *tok;
944 unsigned char toklen;
948 toklen = strlen(tok);
949 if ((_bufLen - pos) < toklen)
950 /* remaining string not long enough */
954 ? strncmp(&(_buf[pos]), tok, toklen)
955 : strncasecmp(&(_buf[pos]), tok, toklen);
959 if (!(_buf[pos + toklen] == '\0' || isspace(_buf[pos + toklen])))
960 /* not at the string end or folloed by a space */
963 /* wow, found the token */
964 pos += toklen; /* skip it */
969 /* next, check for STRING */
971 if ((c == '\'') || (c == '"')) {
973 char string[_bufLen - pos];
977 while (pos < _bufLen) {
981 if ((ch == '\\') && (_bufLen > (pos + 1))) {
982 if (_buf[pos + 1] == c) {
990 if (pos >= _bufLen) {
991 NSLog(@"WARNING(%s): found end of string before end of quoted text",
992 __PRETTY_FUNCTION__);
995 res = [StringClass stringWithCString:string length:cnt];
996 pos++; /* don`t forget quotations */
997 if (qDebug) NSLog(@"_parseValue return <%@> for <%s> ", res, _buf);
1002 /* complete parsing of cast */
1003 if (parseComplexCast && (pos + 6) < _bufLen) {
1004 /* now we need " as 'dateTime'" [min 7 #] */
1007 while (isspace(_buf[pos]) && pos < _bufLen) pos++;
1009 //printf("POS: '%s'\n", &(_buf[pos]));
1011 if (_buf[pos] != 'a' && _buf[pos] != 'A')
1012 NSLog(@"%s: expecting 'AS' of complex cast ...", __PRETTY_FUNCTION__);
1013 else if (_buf[pos + 1] != 's' && _buf[pos + 1] != 'S')
1014 NSLog(@"%s: expecting 'AS' of complex cast ...", __PRETTY_FUNCTION__);
1020 while (isspace(_buf[pos]) && pos < _bufLen) pos++;
1022 /* read cast type */
1023 if (_buf[pos] != '\'') {
1024 NSLog(@"%s: expected type of complex cast ...", __PRETTY_FUNCTION__);
1027 const unsigned char *cs, *ce;
1029 //printf("POS: '%s'\n", &(_buf[pos]));
1032 ce = index(cs, '\'');
1033 cast = [NSString stringWithCString:cs length:(ce - cs)];
1035 NSLog(@"%s: parsed complex cast: '%@' to '%@'", __PRETTY_FUNCTION__,
1041 //printf("POS: '%s'\n", &(_buf[pos]));
1047 if (cast != nil && obj != nil) {
1051 if ((class = [EOQualifierParserTypeMappings objectForKey:cast]) == nil) {
1052 /* no value explicitly mapped to class, try to construct class name... */
1053 NSString *className;
1056 if ((class = NSClassFromString(className)) == Nil) {
1057 /* check some default cast types ... */
1058 className = [cast lowercaseString];
1060 if ([className isEqualToString:@"datetime"])
1061 class = [NSCalendarDate class];
1062 else if ([className isEqualToString:@"datetime.tz"])
1063 class = [NSCalendarDate class];
1067 obj = [[[class alloc] initWithString:[orig description]] autorelease];
1070 NSLog(@"%s: could not init object '%@' of cast class %@(%@) !",
1071 __PRETTY_FUNCTION__, orig, class, cast);
1076 NSLog(@"WARNING(%s): could not map cast '%@' to a class "
1077 @"(returning null) !",
1078 __PRETTY_FUNCTION__, cast);
1084 NSLog(@"%s: return <%@> for <%s> ", __PRETTY_FUNCTION__,
1085 obj?obj:@"<nil>", _buf);
1089 id keys[2], values[2];
1091 keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
1092 keys[1] = @"object"; values[1] = obj;
1095 [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
1096 forFunction:@"parseValue" atPos:(unsigned)_buf];
1102 static EOQualifier *_testOperator(id _ctx, const char *_buf,
1103 unsigned _bufLen, unsigned *_opLen,
1106 EOQualifier *qual = nil;
1107 char c0, c1, c2 = 0;
1108 unsigned pos, len = 0;
1110 pos = _countWhiteSpaces(_buf, _bufLen);
1112 if (_bufLen < 4) {/* at least OR or AND and somethink more */
1114 NSLog(@"_testOperator return nil for <%s> ", _buf);
1121 if (((c0 == 'a') || (c0 == 'A')) &&
1122 ((c1 == 'n') || (c1 == 'N')) &&
1123 ((c2 == 'd') || (c2 == 'D'))) {
1127 else if (((c0 == 'o') || (c0 == 'O')) && ((c1 == 'r') || (c1 == 'R'))) {
1131 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
1132 qual = _parseSingleQualifier(_ctx, _buf + pos, _bufLen - pos, &len);
1133 *_opLen = pos + len;
1135 NSLog(@"_testOperator return %@ for <%s> ", qual, _buf);
1140 static EOQualifier *_parseCompoundQualifier(id _ctx, const char *_buf,
1141 unsigned _bufLen, unsigned *_qualLen)
1143 EOQualifier *q0, *q1 = nil;
1144 NSMutableArray *array = nil;
1145 unsigned pos, len = 0;
1146 EOQualifier *result;
1151 if ((q0 = _parseSingleQualifier(_ctx, _buf, _bufLen, &len)) == nil) {
1153 NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
1159 if (!(q1 = _testOperator(_ctx, _buf + pos, _bufLen - pos, &len, &isAnd))) {
1161 NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
1165 array = [NSMutableArray arrayWithObjects:q0, q1, nil];
1171 q0 = _testOperator(_ctx, _buf + pos, _bufLen - pos, &len, &newIsAnd);
1176 if (newIsAnd != isAnd) {
1179 a = [[array copy] autorelease];
1182 ? [_ctx andQualifierWithArray:a]
1183 : [_ctx orQualifierWithArray:a];
1185 [array removeAllObjects];
1186 [array addObject:q1];
1189 [array addObject:q0];
1196 ? [_ctx andQualifierWithArray:array]
1197 : [_ctx orQualifierWithArray:array];
1200 NSLog(@"_parseAndOrQualifier return <%@> for <%s> ", result, _buf);
1205 static inline unsigned _countWhiteSpaces(const char *_buf, unsigned _bufLen) {
1210 NSLog(@"_parseString _bufLen == 0 --> return nil");
1214 while (_buf[cnt] == ' ' || _buf[cnt] == '\t' ||
1215 _buf[cnt] == '\n' || _buf[cnt] == '\r') {