2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "EOQualifier.h"
27 //#define USE_DESCRIPTION_FOR_AT 1
29 static int qDebug = 0;
30 static NSMutableDictionary *EOQualifierParserTypeMappings = nil;
33 The literals understood by the value parser.
35 NOTE: Any literal used here can never be used as a key ! So add as little
39 const unsigned char *token;
44 static EOQPTokEntry toks[] = {
45 { (const unsigned char *)"NULL", nil, 0 },
46 { (const unsigned char *)"nil", nil, 1 },
47 { (const unsigned char *)"YES", nil, 0 },
48 { (const unsigned char *)"NO", nil, 0 },
49 { (const unsigned char *)"TRUE", nil, 0 },
50 { (const unsigned char *)"FALSE", nil, 0 },
51 { (const unsigned char *)NULL, nil, 0 }
54 static inline void _setupLiterals(void) {
55 static BOOL didSetup = NO;
58 toks[0].value = [[NSNull null] retain];
59 toks[1].value = toks[0].value;
60 toks[2].value = [[NSNumber numberWithBool:YES] retain];
61 toks[3].value = [[NSNumber numberWithBool:NO] retain];
62 toks[4].value = toks[2].value;
63 toks[5].value = toks[3].value;
67 static Class StringClass = Nil;
68 static Class NumberClass = Nil;
69 static EONull *null = nil;
71 /* parsing functions */
73 static EOQualifier *_parseCompoundQualifier(id _ctx, const char *_buf,
74 unsigned _bufLen, unsigned *_qualLen);
75 static EOQualifier *_testOperator(id _ctx, const char *_buf,
76 unsigned _bufLen, unsigned *_opLen,
78 static EOQualifier *_parseQualifiers(id _ctx, const char *_buf,
79 unsigned _bufLen, unsigned *_qualLen);
80 static EOQualifier *_parseParenthesisQualifier(id _ctx,
81 const char *_buf, unsigned _bufLen,
83 static EOQualifier *_parseNotQualifier(id _ctx, const char *_buf,
84 unsigned _bufLen, unsigned *_qualLen);
85 static EOQualifier *_parseKeyCompQualifier(id _ctx, const char *_buf,
86 unsigned _bufLen, unsigned *_qualLen);
87 static NSString *_parseKey(id _ctx, const char *_buf, unsigned _bufLen,
89 static id _parseValue(id _ctx, const char *_buf, unsigned _bufLen,
91 static inline unsigned _countWhiteSpaces(const char *_buf, unsigned _bufLen);
92 static NSString *_parseOp(const char *_buf, unsigned _bufLen,
95 @interface EOQualifierParserContext : NSObject
97 NSMapTable *qualifierCache;
99 - (NSDictionary *)resultForFunction:(NSString *)_fct atPos:(unsigned)_pos;
100 - (void)setResult:(NSDictionary *)_dict forFunction:(NSString *)_fct
101 atPos:(unsigned)_pos;
102 - (id)getObjectFromStackFor:(char)_c;
106 - (EOQualifier *)keyComparisonQualifierWithLeftKey:(NSString *)_leftKey
107 operatorSelector:(SEL)_sel
108 rightKey:(NSString *)_rightKey;
109 - (EOQualifier *)keyValueQualifierWithKey:(NSString *)_key
110 operatorSelector:(SEL)_sel
112 - (EOQualifier *)andQualifierWithArray:(NSArray *)_qualifiers;
113 - (EOQualifier *)orQualifierWithArray:(NSArray *)_qualifiers;
114 - (EOQualifier *)notQualifierWithQualifier:(EOQualifier *)_qualifier;
118 @interface EOQualifierVAParserContext : EOQualifierParserContext
122 + (id)contextWithVaList:(va_list *)_va;
123 - (id)initWithVaList:(va_list *)_va;
126 @interface EOQualifierEnumeratorParserContext : EOQualifierParserContext
128 NSEnumerator *enumerator;
130 + (id)contextWithEnumerator:(NSEnumerator *)_enumerator;
131 - (id)initWithEnumerator:(NSEnumerator *)_enumerator;
134 @implementation EOQualifierVAParserContext
136 + (id)contextWithVaList:(va_list *)_va {
137 return [[[EOQualifierVAParserContext alloc] initWithVaList:_va] autorelease];
140 - (id)initWithVaList:(va_list *)_va {
141 if ((self = [super init])) {
147 - (id)getObjectFromStackFor:(char)_c {
150 if (StringClass == Nil) StringClass = [NSString class];
151 if (NumberClass == Nil) NumberClass = [NSNumber class];
152 if (null == nil) null = [EONull null];
155 char *str = va_arg(*self->va, char*);
156 obj = [StringClass stringWithCString:str];
158 else if (_c == 'd') {
159 int i= va_arg(*self->va, int);
160 obj = [NumberClass numberWithInt:i];
162 else if (_c == 'f') {
163 double d = va_arg(*self->va, double);
164 obj = [NumberClass numberWithDouble:d];
166 else if (_c == '@') {
167 id o = va_arg(*self->va, id);
168 #if USE_DESCRIPTION_FOR_AT
169 obj = (o == nil) ? (id)null : (id)[o description];
171 obj = (o == nil) ? (id)null : (id)o;
175 [NSException raise:@"NSInvalidArgumentException"
176 format:@"unknown conversation char %c", _c];
181 @end /* EOQualifierVAParserContext */
183 @implementation EOQualifierEnumeratorParserContext
185 + (id)contextWithEnumerator:(NSEnumerator *)_enumerator {
186 return [[[EOQualifierEnumeratorParserContext alloc]
187 initWithEnumerator:_enumerator] autorelease];
190 - (id)initWithEnumerator:(NSEnumerator *)_enumerator {
191 if ((self = [super init])) {
192 ASSIGN(self->enumerator, _enumerator);
198 [self->enumerator release];
202 - (id)getObjectFromStackFor:(char)_c {
203 static Class NumberClass = Nil;
206 if (NumberClass == Nil) NumberClass = [NSNumber class];
208 o = [self->enumerator nextObject];
211 #if USE_DESCRIPTION_FOR_AT
212 return [o description];
218 return [NumberClass numberWithDouble:[o doubleValue]];
221 return [NumberClass numberWithInt:[o intValue]];
224 // return [NSString stringWithCString:[o cString]];
225 return [[o copy] autorelease];
228 [NSException raise:@"NSInvalidArgumentException"
229 format:@"unknown or not allowed conversation char %c", _c];
234 @end /* EOQualifierEnumeratorParserContext */
236 @implementation EOQualifierParserContext
239 if (StringClass == Nil) StringClass = [NSString class];
241 if ((self = [super init])) {
242 self->qualifierCache = NSCreateMapTable(NSObjectMapKeyCallBacks,
243 NSObjectMapValueCallBacks,
250 if (self->qualifierCache) NSFreeMapTable(self->qualifierCache);
254 - (NSDictionary *)resultForFunction:(NSString *)_fct atPos:(unsigned)_pos
256 return NSMapGet(self->qualifierCache,
257 [StringClass stringWithFormat:@"%@_%d", _fct, _pos]);
260 - (void)setResult:(NSDictionary *)_dict forFunction:(NSString *)_fct
263 NSMapInsert(self->qualifierCache,
264 [StringClass stringWithFormat:@"%@_%d", _fct, _pos],
268 - (id)getObjectFromStackFor:(char)_c {
269 [self doesNotRecognizeSelector:_cmd];
275 - (EOQualifier *)keyComparisonQualifierWithLeftKey:(NSString *)_leftKey
276 operatorSelector:(SEL)_sel
277 rightKey:(NSString *)_rightKey
279 static Class clazz = Nil;
280 if (clazz == Nil) clazz = [EOKeyComparisonQualifier class];
282 return [[[clazz alloc]
283 initWithLeftKey:_leftKey
284 operatorSelector:_sel
288 - (EOQualifier *)keyValueQualifierWithKey:(NSString *)_key
289 operatorSelector:(SEL)_sel
292 static Class clazz = Nil;
293 if (clazz == Nil) clazz = [EOKeyValueQualifier class];
295 return [[[clazz alloc]
297 operatorSelector:_sel
301 - (EOQualifier *)andQualifierWithArray:(NSArray *)_qualifiers {
302 static Class clazz = Nil;
303 if (clazz == Nil) clazz = [EOAndQualifier class];
305 return [[[clazz alloc] initWithQualifierArray:_qualifiers] autorelease];
307 - (EOQualifier *)orQualifierWithArray:(NSArray *)_qualifiers {
308 static Class clazz = Nil;
309 if (clazz == Nil) clazz = [EOOrQualifier class];
311 return [[[clazz alloc] initWithQualifierArray:_qualifiers] autorelease];
314 - (EOQualifier *)notQualifierWithQualifier:(EOQualifier *)_qualifier {
315 static Class clazz = Nil;
316 if (clazz == Nil) clazz = [EONotQualifier class];
318 return [[[clazz alloc] initWithQualifier:_qualifier] autorelease];
321 - (EOQualifierVariable *)variableWithKey:(NSString *)_key {
322 static Class clazz = Nil;
323 if (clazz == Nil) clazz = [EOQualifierVariable class];
325 return [clazz variableWithKey:_key];
328 @end /* EOQualifierParserContext */
330 @implementation EOQualifier(Parsing)
332 + (void)registerValueClass:(Class)_valueClass forTypeName:(NSString *)_type {
333 if (EOQualifierParserTypeMappings == nil)
334 EOQualifierParserTypeMappings = [[NSMutableDictionary alloc] init];
337 NSLog(@"ERROR(%s): got passed no type name!", __PRETTY_FUNCTION__);
340 if (_valueClass == nil) {
341 NSLog(@"ERROR(%s): got passed no value-class for type '%@'!",
342 __PRETTY_FUNCTION__, _type);
346 [EOQualifierParserTypeMappings setObject:_valueClass forKey:_type];
349 + (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat,... {
351 EOQualifier *qualifier;
358 if (StringClass == Nil) StringClass = [NSString class];
360 bufLen = [_qualifierFormat cStringLength];
361 cbuf = malloc(bufLen + 1);
362 [_qualifierFormat getCString:cbuf]; cbuf[bufLen] = '\0';
365 va_start(va, _qualifierFormat);
367 _parseQualifiers([EOQualifierVAParserContext contextWithVaList:&va],
368 buf, bufLen, &length);
371 if (qualifier != nil) { /* check whether the rest of the string is OK */
373 length += _countWhiteSpaces(buf + length, bufLen - length);
375 if (length < bufLen) {
376 NSLog(@"WARNING(%s): unexpected chars at the end of the "
377 @"string(class=%@,len=%i) '%@'",
379 [_qualifierFormat class],
380 [_qualifierFormat length], _qualifierFormat);
381 NSLog(@" buf-length: %i", bufLen);
382 NSLog(@" length: %i", length);
383 NSLog(@" char[length]: '%c' (%i) '%s'", buf[length], buf[length],
387 else if (length > bufLen) {
388 NSLog(@"WARNING(%s): length should never be longer than bufLen ?, "
389 @"internal parsing error !",
390 __PRETTY_FUNCTION__);
397 + (EOQualifier *)qualifierWithQualifierFormat:(NSString *)_qualifierFormat
398 arguments:(NSArray *)_arguments
400 EOQualifier *qual = nil;
402 const char *buf = NULL;
404 EOQualifierEnumeratorParserContext *ctx;
407 if (StringClass == Nil) StringClass = [NSString class];
409 ctx = [EOQualifierEnumeratorParserContext contextWithEnumerator:
410 [_arguments objectEnumerator]];
412 //NSLog(@"qclass: %@", [_qualifierFormat class]);
413 buf = [_qualifierFormat cString];
414 bufLen = [_qualifierFormat cStringLength];
415 qual = _parseQualifiers(ctx, buf, bufLen, &length);
417 if (qual != nil) { /* check whether the rest of the string is OK */
418 if (length < bufLen) {
419 length += _countWhiteSpaces(buf + length, bufLen - length);
421 if (length != bufLen) {
422 NSLog(@"WARNING(%s): unexpected chars at the end of the string '%@'",
423 __PRETTY_FUNCTION__, _qualifierFormat);
430 @end /* EOQualifier(Parsing) */
432 static EOQualifier *_parseSingleQualifier(id _ctx, const char *_buf,
436 EOQualifier *res = nil;
438 if ((res = _parseParenthesisQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
440 NSLog(@"_parseSingleQualifier return <%@> for <%s> ", res, _buf);
444 if ((res = _parseNotQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
446 NSLog(@"_parseSingleQualifier return <%@> for <%s> ", res, _buf);
450 if ((res = _parseKeyCompQualifier(_ctx, _buf, _bufLen, _qualLen)) != nil) {
452 NSLog(@"_parseSingleQualifier return <%@> for <%s> length %d",
453 res, _buf, *_qualLen);
460 static EOQualifier *_parseQualifiers(id _ctx, const char *_buf, unsigned _bufLen,
463 EOQualifier *res = nil;
466 if ((res = _parseCompoundQualifier(_ctx, _buf, _bufLen, _qualLen))) {
468 NSLog(@"_parseQualifiers return <%@> for <%s> ", res, _buf);
472 if ((res = _parseSingleQualifier(_ctx, _buf, _bufLen, _qualLen))) {
474 NSLog(@"_parseQualifiers return <%@> for <%s> ", res, _buf);
479 NSLog(@"_parseQualifiers return nil for <%s> ", _buf);
484 static EOQualifier *_parseParenthesisQualifier(id _ctx, const char *_buf,
489 unsigned qualLen = 0;
490 EOQualifier *qual = nil;
492 pos = _countWhiteSpaces(_buf, _bufLen);
494 if (_bufLen <= pos + 2) /* at least open and close parenthesis */ {
496 NSLog(@"1_parseParenthesisQualifier return nil for <%s> ", _buf);
500 if (_buf[pos] != '(') {
502 NSLog(@"2_parseParenthesisQualifier return nil for <%s> ", _buf);
507 if (!(qual = _parseQualifiers(_ctx, _buf + pos, _bufLen - pos,
510 NSLog(@"3_parseParenthesisQualifier return nil for <%s> ", _buf);
516 if (_bufLen <= pos) {
518 NSLog(@"4_parseParenthesisQualifier return nil for <%s> qual[%@] %@ bufLen %d "
519 @"pos %d", _buf, [qual class], qual, _bufLen, pos);
523 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
524 if (_buf[pos] != ')') {
526 NSLog(@"5_parseParenthesisQualifier return nil for <%s> [%s] ", _buf, _buf+pos);
531 NSLog(@"6_parseParenthesisQualifier return <%@> for <%s> ", qual, _buf);
533 *_qualLen = pos + 1; /* one step after the parenthesis */
537 static EOQualifier *_parseNotQualifier(id _ctx, const char *_buf,
538 unsigned _bufLen, unsigned *_qualLen)
540 unsigned pos, len = 0;
542 EOQualifier *qual = nil;
544 pos = _countWhiteSpaces(_buf, _bufLen);
546 if (_bufLen - pos < 4) { /* at least 3 chars for 'NOT' */
548 NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
555 if (!(((c0 == 'n') || (c0 == 'N')) &&
556 ((c1 == 'o') || (c1 == 'O')) &&
557 ((c2 == 't') || (c2 == 'T')))) {
559 NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
563 qual = _parseSingleQualifier(_ctx, _buf + pos, _bufLen - pos, &len);
566 NSLog(@"_parseNotQualifier return nil for <%s> ", _buf);
570 *_qualLen = pos +len;
572 NSLog(@"_parseNotQualifier return %@ for <%s> ", qual, _buf);
574 return [_ctx notQualifierWithQualifier:qual];
577 static EOQualifier *_parseKeyCompQualifier(id _ctx, const char *_buf,
578 unsigned _bufLen, unsigned *_qualLen)
582 NSString *value = nil;
583 EOQualifier *qual = nil;
584 NSDictionary *dict = nil;
588 BOOL valueIsKey = NO;
590 dict = [_ctx resultForFunction:@"parseKeyCompQualifier"
591 atPos:(unsigned long)_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 long)_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 long)_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 long)_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 long)_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((const char *)tok);
949 if ((_bufLen - pos) < toklen)
950 /* remaining string not long enough */
954 ? strncmp(&(_buf[pos]), (const char *)tok, toklen)
955 : strncasecmp(&(_buf[pos]), (const char *)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]));
1031 cs = (const unsigned char *)&(_buf[pos]);
1032 ce = (const unsigned char *)index((const char *)cs, '\'');
1033 cast = [NSString stringWithCString:(const char*)cs length:(ce - cs)];
1035 NSLog(@"%s: parsed complex cast: '%@' to '%@'",
1036 __PRETTY_FUNCTION__, obj, cast);
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 != nil ? obj : (id)@"<nil>", _buf);
1090 id keys[2], values[2];
1092 keys[0] = @"length"; values[0] = [NSNumber numberWithUnsignedInt:pos];
1093 keys[1] = @"object"; values[1] = obj;
1095 d = [[NSDictionary alloc] initWithObjects:values forKeys:keys count:2];
1096 [_ctx setResult:d forFunction:@"parseValue" atPos:(unsigned long)_buf];
1103 static EOQualifier *_testOperator(id _ctx, const char *_buf,
1104 unsigned _bufLen, unsigned *_opLen,
1107 EOQualifier *qual = nil;
1108 char c0, c1, c2 = 0;
1109 unsigned pos, len = 0;
1111 pos = _countWhiteSpaces(_buf, _bufLen);
1113 if (_bufLen < 4) {/* at least OR or AND and somethink more */
1115 NSLog(@"_testOperator return nil for <%s> ", _buf);
1122 if (((c0 == 'a') || (c0 == 'A')) &&
1123 ((c1 == 'n') || (c1 == 'N')) &&
1124 ((c2 == 'd') || (c2 == 'D'))) {
1128 else if (((c0 == 'o') || (c0 == 'O')) && ((c1 == 'r') || (c1 == 'R'))) {
1132 pos += _countWhiteSpaces(_buf + pos, _bufLen - pos);
1133 qual = _parseSingleQualifier(_ctx, _buf + pos, _bufLen - pos, &len);
1134 *_opLen = pos + len;
1136 NSLog(@"_testOperator return %@ for <%s> ", qual, _buf);
1141 static EOQualifier *_parseCompoundQualifier(id _ctx, const char *_buf,
1142 unsigned _bufLen, unsigned *_qualLen)
1144 EOQualifier *q0, *q1 = nil;
1145 NSMutableArray *array = nil;
1146 unsigned pos, len = 0;
1147 EOQualifier *result;
1152 if ((q0 = _parseSingleQualifier(_ctx, _buf, _bufLen, &len)) == nil) {
1154 NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
1160 if (!(q1 = _testOperator(_ctx, _buf + pos, _bufLen - pos, &len, &isAnd))) {
1162 NSLog(@"_parseAndOrQualifier return nil for <%s> ", _buf);
1166 array = [NSMutableArray arrayWithObjects:q0, q1, nil];
1172 q0 = _testOperator(_ctx, _buf + pos, _bufLen - pos, &len, &newIsAnd);
1177 if (newIsAnd != isAnd) {
1180 a = [[array copy] autorelease];
1183 ? [_ctx andQualifierWithArray:a]
1184 : [_ctx orQualifierWithArray:a];
1186 [array removeAllObjects];
1187 [array addObject:q1];
1190 [array addObject:q0];
1197 ? [_ctx andQualifierWithArray:array]
1198 : [_ctx orQualifierWithArray:array];
1201 NSLog(@"_parseAndOrQualifier return <%@> for <%s> ", result, _buf);
1206 static inline unsigned _countWhiteSpaces(const char *_buf, unsigned _bufLen) {
1211 NSLog(@"_parseString _bufLen == 0 --> return nil");
1215 while (_buf[cnt] == ' ' || _buf[cnt] == '\t' ||
1216 _buf[cnt] == '\n' || _buf[cnt] == '\r') {