2 Copyright (C) 2000-2007 SKYRIX Software AG
3 Copyright (C) 2007 Helge Hess
5 This file is part of SOPE.
7 SOPE is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with SOPE; see the file COPYING. If not, write to the
19 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[] = {
46 { (const unsigned char *)"NULL", nil, 0 },
47 { (const unsigned char *)"nil", nil, 1 },
48 { (const unsigned char *)"YES", nil, 0 },
49 { (const unsigned char *)"NO", nil, 0 },
50 { (const unsigned char *)"TRUE", nil, 0 },
51 { (const unsigned char *)"FALSE", nil, 0 },
52 { (const unsigned char *)NULL, nil, 0 }
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"
592 atPos:(unsigned long)_buf];
595 NSLog(@"_parseKeyCompQual return <%@> [cached] for <%s> ", dict, _buf);
597 *_qualLen = [[dict objectForKey:@"length"] unsignedIntValue];
598 return [dict objectForKey:@"object"];
600 pos = _countWhiteSpaces(_buf, _bufLen);
602 if ((key = _parseKey(_ctx , _buf + pos, _bufLen - pos, &length)) == nil) {
604 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
609 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
611 if (!(op = _parseOp(_buf + pos, _bufLen - pos, &length))) {
613 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
616 sel = [EOQualifier operatorSelectorForString:op];
618 NSLog(@"WARNING(%s): possible unknown operator <%@>", __PRETTY_FUNCTION__,
621 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
625 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
628 value = _parseValue(_ctx, _buf + pos, _bufLen - pos, &length);
630 value = _parseKey(_ctx, _buf + pos, _bufLen - pos, &length);
633 NSLog(@"_parseKeyCompQualifier return nil for <%s> ", _buf);
643 ? [_ctx keyComparisonQualifierWithLeftKey:key
646 : [_ctx keyValueQualifierWithKey:key
651 NSLog(@"_parseKeyCompQualifier return <%@> for <%s> ", qual, _buf);
654 id keys[2], values[2];
655 keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
656 keys[1] = @"object"; values[1] = qual;
658 [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
659 forFunction:@"parseKeyCompQualifier"
660 atPos:(unsigned long)_buf];
666 static NSString *_parseOp(const char *_buf, unsigned _bufLen,
675 NSLog(@"_parseOp _bufLen == 0 --> return nil");
678 pos = _countWhiteSpaces(_buf, _bufLen);
679 if (_bufLen - pos > 1) {/* at least an operation and a value */
683 if (((c0 >= '<') && (c0 <= '>')) || (c0 == '!')) {
686 if ((c1 >= '<') && (c1 <= '>')) {
688 result = [StringClass stringWithCString:_buf + pos length:2];
690 NSLog(@"_parseOp return <%@> for <%s> ", result, _buf);
694 result = [StringClass stringWithCString:&c0 length:1];
696 NSLog(@"_parseOp return <%@> for <%s> ", result, _buf);
700 else { /* string designator operator */
701 unsigned opStart = pos;
702 while (pos < _bufLen) {
703 if (_buf[pos] == ' ')
707 if (pos >= _bufLen) {
708 NSLog(@"WARNING(%s): found end of string during operator parsing",
709 __PRETTY_FUNCTION__);
713 NSLog(@"%s: _parseOp return <%@> for <%s> ", __PRETTY_FUNCTION__,
714 [StringClass stringWithCString:_buf + opStart
715 length:pos - opStart], _buf);
719 return [StringClass stringWithCString:_buf + opStart length:pos - opStart];
723 NSLog(@"_parseOp return nil for <%s> ", _buf);
727 static NSString *_parseKey(id _ctx, const char *_buf, unsigned _bufLen,
731 NSDictionary *dict = nil;
733 unsigned startKey = 0;
737 if (qDebug) NSLog(@"%s: _bufLen == 0 --> return nil", __PRETTY_FUNCTION__);
740 dict = [_ctx resultForFunction:@"parseKey" atPos:(unsigned long)_buf];
743 NSLog(@"%s: return <%@> [cached] for <%s> ", __PRETTY_FUNCTION__,
746 *_keyLen = [[dict objectForKey:@"length"] unsignedIntValue];
747 return [dict objectForKey:@"object"];
749 pos = _countWhiteSpaces(_buf, _bufLen);
754 if (_bufLen - pos < 2) {
756 NSLog(@"%s: [c==%%,bufLen-pos<2]: _parseValue return nil for <%s> ",
757 __PRETTY_FUNCTION__, _buf);
762 result = [_ctx getObjectFromStackFor:_buf[pos]];
766 /* '{' for namspaces */
767 register BOOL isQuotedKey = NO;
771 else if (!(((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
774 NSLog(@"%s: [c!=AZaz{]: _parseKey return nil for <%s> ",
775 __PRETTY_FUNCTION__, _buf);
781 while (pos < _bufLen) {
783 if (isQuotedKey && c == '"')
786 ((c == ' ') || (c == '<') || (c == '>') || (c == '=') || (c == '!') ||
787 c == ')' || c == '(')
793 result = [StringClass stringWithCString:(_buf + startKey + 1)
794 length:(pos - startKey - 2)];
797 result = [StringClass stringWithCString:(_buf + startKey)
798 length:(pos - startKey)];
803 NSLog(@"%s: return <%@> for <%s> ", __PRETTY_FUNCTION__, result, _buf);
806 id keys[2], values[2];
808 keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
809 keys[1] = @"object"; values[1] = result;
812 [NSDictionary dictionaryWithObjects:values forKeys:keys count:2]
813 forFunction:@"parseKey"
814 atPos:(unsigned long)_buf];
820 static id _parseValue(id _ctx, const char *_buf, unsigned _bufLen,
823 NSString *cast = nil;
824 NSDictionary *dict = nil;
829 if (NumberClass == Nil) NumberClass = [NSNumber class];
830 if (null == nil) null = [[NSNull null] retain];
833 if (qDebug) NSLog(@"_parseValue _bufLen == 0 --> return nil");
837 dict = [_ctx resultForFunction:@"parseValue" atPos:(unsigned long)_buf];
840 NSLog(@"_parseKeyCompQualifier return <%@> [cached] for <%s> ",
843 *_keyLen = [[dict objectForKey:@"length"] unsignedIntValue];
844 return [dict objectForKey:@"object"];
847 pos = _countWhiteSpaces(_buf, _bufLen);
850 if (c == '$') { /* found EOQualifierVariable */
851 unsigned startVar = 0;
856 while (pos < _bufLen) {
857 if ((_buf[pos] == ' ') || (_buf[pos] == ')'))
862 varKey = [StringClass stringWithCString:(_buf + startVar)
863 length:pos - startVar];
864 obj = [_ctx variableWithKey:varKey];
867 /* first, check for CAST */
868 BOOL parseComplexCast = NO;
870 if (c == 'c' && _bufLen > 14) {
871 if (strstr(_buf, "cast") == _buf && (isspace(_buf[4]) || _buf[4]=='(')) {
872 /* for example: cast("1970-01-01T00:00:00Z" as 'dateTime') [min 15 #]*/
873 pos += 4; /* skip 'cast' */
874 while (isspace(_buf[pos])) /* skip spaces */
876 if (_buf[pos] != '(') {
877 NSLog(@"WARNING(%s): got unexpected cast string: '%s'",
878 __PRETTY_FUNCTION__, _buf);
881 pos++; /* skip opening bracket '(' */
883 parseComplexCast = YES;
887 else if (c == '(') { /* starting with a cast */
888 /* for example: (NSCalendarDate)"1999-12-12" [min 5 chars] */
889 unsigned startCast = 0;
893 while (pos < _bufLen) {
894 if (_buf[pos] == ')')
899 if (pos >= _bufLen) {
900 NSLog(@"WARNING(%s): found end of string while reading a cast",
901 __PRETTY_FUNCTION__);
905 cast = [StringClass stringWithCString:(_buf + startCast)
906 length:(pos - 1 - startCast)];
908 NSLog(@"%s: got cast %@", __PRETTY_FUNCTION__, cast);
911 /* next, check for FORMAT SPECIFIER */
913 if (_bufLen - pos < 2) {
915 NSLog(@"_parseValue return nil for <%s> ", _buf);
920 obj = [_ctx getObjectFromStackFor:_buf[pos]];
924 /* next, check for A NUMBER */
925 else if (((c >= '0') && (c <= '9')) || (c == '-')) { /* got a number */
926 unsigned startNumber;
930 while (pos < _bufLen) {
932 if (!((c >= '0') && (c <= '9')))
936 obj = [NumberClass numberWithInt:atoi(_buf + startNumber)];
939 /* check for some text literals */
940 if ((obj == nil) && ((_bufLen - pos) > 1)) {
943 for (i = 0; i < 20 && (toks[i].token != NULL) && (obj == nil); i++) {
944 const unsigned char *tok;
945 unsigned char toklen;
949 toklen = strlen((const char *)tok);
950 if ((_bufLen - pos) < toklen)
951 /* remaining string not long enough */
955 ? strncmp(&(_buf[pos]), (const char *)tok, toklen)
956 : strncasecmp(&(_buf[pos]), (const char *)tok, toklen);
961 if (!(_buf[pos + toklen] == '\0' || isspace(_buf[pos + toklen]) ||
962 _buf[pos + toklen] == ')')) {
964 Not at the string end or followed by a space or a right
965 parenthesis. The latter is required to correctly parse this:
966 (not (attribute = nil) and
967 attribute.className = 'com.webobjects.foundation.NSTimestamp')
972 /* wow, found the token */
973 pos += toklen; /* skip it */
978 /* next, check for STRING */
980 if ((c == '\'') || (c == '"')) {
982 char string[_bufLen - pos];
986 while (pos < _bufLen) {
990 if ((ch == '\\') && (_bufLen > (pos + 1))) {
991 if (_buf[pos + 1] == c) {
999 if (pos >= _bufLen) {
1000 NSLog(@"WARNING(%s): found end of string before end of quoted text",
1001 __PRETTY_FUNCTION__);
1004 res = [StringClass stringWithCString:string length:cnt];
1005 pos++; /* don`t forget quotations */
1006 if (qDebug) NSLog(@"_parseValue return <%@> for <%s> ", res, _buf);
1011 /* complete parsing of cast */
1012 if (parseComplexCast && (pos + 6) < _bufLen) {
1013 /* now we need " as 'dateTime'" [min 7 #] */
1016 while (isspace(_buf[pos]) && pos < _bufLen) pos++;
1018 //printf("POS: '%s'\n", &(_buf[pos]));
1020 if (_buf[pos] != 'a' && _buf[pos] != 'A')
1021 NSLog(@"%s: expecting 'AS' of complex cast ...", __PRETTY_FUNCTION__);
1022 else if (_buf[pos + 1] != 's' && _buf[pos + 1] != 'S')
1023 NSLog(@"%s: expecting 'AS' of complex cast ...", __PRETTY_FUNCTION__);
1029 while (isspace(_buf[pos]) && pos < _bufLen) pos++;
1031 /* read cast type */
1032 if (_buf[pos] != '\'') {
1033 NSLog(@"%s: expected type of complex cast ...", __PRETTY_FUNCTION__);
1036 const unsigned char *cs, *ce;
1038 //printf("POS: '%s'\n", &(_buf[pos]));
1040 cs = (const unsigned char *)&(_buf[pos]);
1041 ce = (const unsigned char *)index((const char *)cs, '\'');
1042 cast = [NSString stringWithCString:(const char*)cs length:(ce - cs)];
1044 NSLog(@"%s: parsed complex cast: '%@' to '%@'",
1045 __PRETTY_FUNCTION__, obj, cast);
1050 //printf("POS: '%s'\n", &(_buf[pos]));
1056 if (cast != nil && obj != nil) {
1060 if ((class = [EOQualifierParserTypeMappings objectForKey:cast]) == nil) {
1061 /* no value explicitly mapped to class, try to construct class name... */
1062 NSString *className;
1065 if ((class = NSClassFromString(className)) == Nil) {
1066 /* check some default cast types ... */
1067 className = [cast lowercaseString];
1069 if ([className isEqualToString:@"datetime"])
1070 class = [NSCalendarDate class];
1071 else if ([className isEqualToString:@"datetime.tz"])
1072 class = [NSCalendarDate class];
1076 obj = [[[class alloc] initWithString:[orig description]] autorelease];
1079 NSLog(@"%s: could not init object '%@' of cast class %@(%@) !",
1080 __PRETTY_FUNCTION__, orig, class, cast);
1085 NSLog(@"WARNING(%s): could not map cast '%@' to a class "
1086 @"(returning null) !",
1087 __PRETTY_FUNCTION__, cast);
1093 NSLog(@"%s: return <%@> for <%s> ", __PRETTY_FUNCTION__,
1094 obj != nil ? obj : (id)@"<nil>", _buf);
1099 id keys[2], values[2];
1101 keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
1102 keys[1] = @"object"; values[1] = obj;
1104 d = [[NSDictionary alloc] initWithObjects:values forKeys:keys count:2];
1105 [_ctx setResult:d forFunction:@"parseValue" atPos:(unsigned long)_buf];
1112 static EOQualifier *_testOperator(id _ctx, const char *_buf,
1113 unsigned _bufLen, unsigned *_opLen,
1116 EOQualifier *qual = nil;
1117 char c0, c1, c2 = 0;
1118 unsigned pos, len = 0;
1120 pos = _countWhiteSpaces(_buf, _bufLen);
1122 if (_bufLen < 4) {/* at least OR or AND and somethink more */
1124 NSLog(@"_testOperator return nil for <%s> ", _buf);
1131 if (((c0 == 'a') || (c0 == 'A')) &&
1132 ((c1 == 'n') || (c1 == 'N')) &&
1133 ((c2 == 'd') || (c2 == 'D'))) {
1137 else if (((c0 == 'o') || (c0 == 'O')) && ((c1 == 'r') || (c1 == 'R'))) {
1141 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
1142 qual = _parseSingleQualifier(_ctx, _buf + pos, _bufLen - pos, &len);
1143 *_opLen = pos + len;
1145 NSLog(@"_testOperator return %@ for <%s> ", qual, _buf);
1150 static EOQualifier *_parseCompoundQualifier(id _ctx, const char *_buf,
1151 unsigned _bufLen, unsigned *_qualLen)
1153 EOQualifier *q0, *q1 = nil;
1154 NSMutableArray *array = nil;
1155 unsigned pos, len = 0;
1156 EOQualifier *result;
1161 if ((q0 = _parseSingleQualifier(_ctx, _buf, _bufLen, &len)) == nil) {
1163 NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
1169 if (!(q1 = _testOperator(_ctx, _buf + pos, _bufLen - pos, &len, &isAnd))) {
1171 NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
1175 array = [NSMutableArray arrayWithObjects:q0, q1, nil];
1181 q0 = _testOperator(_ctx, _buf + pos, _bufLen - pos, &len, &newIsAnd);
1186 if (newIsAnd != isAnd) {
1189 a = [[array copy] autorelease];
1192 ? [_ctx andQualifierWithArray:a]
1193 : [_ctx orQualifierWithArray:a];
1195 [array removeAllObjects];
1196 [array addObject:q1];
1199 [array addObject:q0];
1206 ? [_ctx andQualifierWithArray:array]
1207 : [_ctx orQualifierWithArray:array];
1210 NSLog(@"_parseAndOrQualifier return <%@> for <%s> ", result, _buf);
1215 static inline unsigned _countWhiteSpaces(const char *_buf, unsigned _bufLen) {
1220 NSLog(@"_parseString _bufLen == 0 --> return nil");
1224 while (_buf[cnt] == ' ' || _buf[cnt] == '\t' ||
1225 _buf[cnt] == '\n' || _buf[cnt] == '\r') {