1 /*								      CSParse.c
2 **	PICS CONFIGURATION MANAGER FOR CLIENTS AND SERVERS
3 **
4 **	(c) COPYRIGHT MIT 1995.
5 **	Please first read the full copyright statement in the file COPYRIGHT.
6 **
7 **	This module converts application/xpics streams (files or network) to PICS_ class data
8 **
9 ** History:
10 **	 4 Dec 95  EGP  start
11 **	15 Feb 96  EGP  alpha 1
12 **
13 ** BUGS: no code yet; doesn't actually do anything
14 */
15 
16 /* Library include files */
17 #include "wwwsys.h"
18 #include "HTChunk.h"
19 #include "HTString.h"
20 #include "CSLUtils.h"
21 #include "CSParse.h"
22 
23 PUBLIC int ParseDebug = 0;	/* For use with LablPars and RatPars */
24 
BVal_readVal(BVal_t * pBVal,const char * valueStr)25 PUBLIC BOOL BVal_readVal(BVal_t * pBVal, const char * valueStr)
26 {
27     if (!strcasecomp(valueStr, "true") ||
28         !strcasecomp(valueStr, "yes"))
29         pBVal->state = BVal_YES;
30     else if (strcasecomp(valueStr, "false") &&
31              strcasecomp(valueStr, "no"))
32         return NO;;
33     pBVal->state |= BVal_INITIALIZED;
34     return YES;
35 }
36 
BVal_initialized(const BVal_t * pBVal)37 PUBLIC BOOL BVal_initialized(const BVal_t * pBVal)
38 {
39     return (pBVal->state & BVal_INITIALIZED);
40 }
41 
BVal_value(const BVal_t * pBVal)42 PUBLIC BOOL BVal_value(const BVal_t * pBVal)
43 {
44     return ((pBVal->state & BVal_YES) ? 1 : 0);
45 }
46 
BVal_set(BVal_t * pBVal,BOOL value)47 PUBLIC void BVal_set(BVal_t * pBVal, BOOL value)
48 {
49 	if (value)
50 		pBVal->state = BVal_YES;
51     pBVal->state |= BVal_INITIALIZED;
52     return;
53 }
54 
BVal_clear(BVal_t * pBVal)55 PUBLIC void BVal_clear(BVal_t * pBVal)
56 {
57     if (pBVal)
58       pBVal->state = BVal_UNINITIALIZED;
59     return;
60 }
61 
FVal_readVal(FVal_t * pFVal,const char * valueStr)62 PUBLIC BOOL FVal_readVal(FVal_t * pFVal, const char * valueStr)
63 {
64     if (!strcasecomp(valueStr, "+INF")) {
65         pFVal->stat = FVal_POSITIVE_INF;
66         return YES;
67     }
68     if (!strcasecomp(valueStr, "-INF")) {
69         pFVal->stat = FVal_NEGATIVE_INF;
70         return YES;
71     }
72     pFVal->stat = FVal_VALUE;
73     sscanf(valueStr, "%f", &pFVal->value);
74     return YES;
75 }
76 
FVal_initialized(const FVal_t * pFVal)77 PUBLIC BOOL FVal_initialized(const FVal_t * pFVal)
78 {
79     return (pFVal->stat != FVal_UNINITIALIZED);
80 }
81 
FVal_value(const FVal_t * pFVal)82 PUBLIC float FVal_value(const FVal_t * pFVal)
83 {
84     return (pFVal->value);
85 }
86 
87 /* C U T T I N G   E D G E   M A T H   T E C H N O L O G Y   H E R E */
FVal_lessThan(const FVal_t * pSmall,const FVal_t * pBig)88 PUBLIC BOOL FVal_lessThan(const FVal_t * pSmall, const FVal_t * pBig)
89 {
90     if (pBig->stat == FVal_UNINITIALIZED || pSmall->stat == FVal_UNINITIALIZED)
91         return FALSE;
92     if (pBig->stat == FVal_POSITIVE_INF || pSmall->stat == FVal_NEGATIVE_INF) {
93         if (pSmall->stat == FVal_POSITIVE_INF)
94             return FALSE;
95         return TRUE;
96     }
97     if (pBig->stat == FVal_NEGATIVE_INF || pSmall->stat == FVal_POSITIVE_INF) {
98         return FALSE;
99     }
100     return pSmall->value < pBig->value;
101 }
102 
FVal_minus(const FVal_t * pBig,const FVal_t * pSmall)103 PUBLIC FVal_t FVal_minus(const FVal_t * pBig, const FVal_t * pSmall)
104 {
105     FVal_t ret = FVal_NEW_UNINITIALIZED;
106     /* no notion of 2 time infinity so please keep your limits to a minimum */
107     if (pBig->stat == FVal_UNINITIALIZED || pSmall->stat == FVal_UNINITIALIZED)
108         return ret;
109     FVal_set(&ret, (float)0.0);
110     if (pBig->stat == FVal_POSITIVE_INF || pSmall->stat == FVal_NEGATIVE_INF) {
111         if (pSmall->stat != FVal_POSITIVE_INF)
112             FVal_setInfinite(&ret, 0);
113         return ret;
114     }
115     if (pBig->stat == FVal_NEGATIVE_INF || pSmall->stat == FVal_POSITIVE_INF) {
116         if (pSmall->stat != FVal_NEGATIVE_INF)
117             FVal_setInfinite(&ret, 0);
118         return ret;
119     }
120     ret.value = pBig->value - pSmall->value;
121     return (ret);
122 }
123 
FVal_nearerZero(const FVal_t * pRef,const FVal_t * pCheck)124 PUBLIC BOOL FVal_nearerZero(const FVal_t * pRef, const FVal_t * pCheck)
125 {
126     if (pRef->stat == FVal_UNINITIALIZED || pCheck->stat == FVal_UNINITIALIZED ||
127         pCheck->stat == FVal_POSITIVE_INF || pCheck->stat == FVal_NEGATIVE_INF)
128         return NO;
129     if (pRef->stat == FVal_POSITIVE_INF || pRef->stat == FVal_NEGATIVE_INF)
130         return YES;
131     if (pRef->value < 0.0) {
132         if (pCheck->value < 0.0)
133             return pCheck->value > pRef->value;
134         return pCheck->value < -pRef->value;
135     }
136     if (pCheck->value < 0.0)
137         return pCheck->value > -pRef->value;
138     return pCheck->value < pRef->value;
139 }
140 
FVal_isZero(const FVal_t * pFVal)141 PUBLIC BOOL FVal_isZero(const FVal_t * pFVal)
142 {
143     if (pFVal->stat == FVal_VALUE && pFVal->value == 0.0)
144         return YES;
145     return NO;
146 }
147 
FVal_set(FVal_t * pFVal,float value)148 PUBLIC void FVal_set(FVal_t * pFVal, float value)
149 {
150     pFVal->value = value;
151     pFVal->stat = FVal_VALUE;
152 }
153 
FVal_setInfinite(FVal_t * pFVal,BOOL negative)154 PUBLIC void FVal_setInfinite(FVal_t * pFVal, BOOL negative)
155 {
156     pFVal->stat = negative ? FVal_NEGATIVE_INF : FVal_POSITIVE_INF;
157 }
158 
FVal_isInfinite(const FVal_t * pFVal)159 PUBLIC int FVal_isInfinite(const FVal_t * pFVal)
160 {
161     return (pFVal->stat == FVal_POSITIVE_INF ? 1 : pFVal->stat == FVal_NEGATIVE_INF ? -1 : 0);
162 }
163 
FVal_clear(FVal_t * pFVal)164 PUBLIC void FVal_clear(FVal_t * pFVal)
165 {
166     if (pFVal)
167       pFVal->stat = FVal_UNINITIALIZED;
168     return;
169 }
170 
FVal_toStr(FVal_t * pFVal)171 PUBLIC char * FVal_toStr(FVal_t * pFVal)
172 {
173     char * ptr;
174     if ((ptr = (char *)HT_MALLOC(40)) == NULL)
175 	HT_OUTOFMEM("FVal buffer");
176     sprintf(ptr, "%.1f", FVal_value(pFVal));
177     return ptr;
178 }
179 
SVal_readVal(SVal_t * pSVal,const char * valueStr)180 PUBLIC BOOL SVal_readVal(SVal_t * pSVal, const char * valueStr)
181 {
182     pSVal->initialized = YES;
183     StrAllocCopy(pSVal->value, valueStr);
184     return YES;
185 }
186 
SVal_initialized(const SVal_t * pSVal)187 PUBLIC BOOL SVal_initialized(const SVal_t * pSVal)
188 {
189     return (pSVal->initialized != NO);
190 }
191 
SVal_value(const SVal_t * pSVal)192 PUBLIC char * SVal_value(const SVal_t * pSVal)
193 {
194     return (pSVal->value);
195 }
196 
SVal_clear(SVal_t * pSVal)197 PUBLIC void SVal_clear(SVal_t * pSVal)
198 {
199     if (SVal_initialized(pSVal)) {
200       HT_FREE(pSVal->value);
201       pSVal->initialized = NO;
202       }
203     return;
204 }
205 
206 #if 0
207     int year;
208     int month;
209     int day;
210     int hour;
211     int minute;
212     int timeZoneHours;
213     int timeZoneMinutes;
214 #endif
DVal_readVal(DVal_t * pDVal,const char * valueStr)215 PUBLIC BOOL DVal_readVal(DVal_t * pDVal, const char * valueStr)
216 {
217     char space[] = "1994.11.05T08:15-0500";
218     char timeZoneSign;
219     char timeZoneMinutesMSB;
220     if (strlen(valueStr) != 0x15)
221         return NO;
222     memcpy(space, valueStr, 0x15);
223     timeZoneSign = space[16];
224     timeZoneMinutesMSB = space[19];
225     space[4] = space[7] = space[10] = space[13] = space[16] = space[19] = 0;
226     pDVal->year = atoi(space);
227     pDVal->month = atoi(space+5);
228     pDVal->day = atoi(space+8);
229     pDVal->hour = atoi(space+11);
230     pDVal->minute = atoi(space+14);
231     pDVal->timeZoneHours = atoi(space+17);
232     space[19] = timeZoneMinutesMSB;
233     pDVal->timeZoneMinutes = atoi(space+19);
234     if (timeZoneSign == '-') {
235         pDVal->timeZoneHours = -pDVal->timeZoneHours;
236         pDVal->timeZoneMinutes = -pDVal->timeZoneMinutes;
237     }
238     StrAllocCopy(pDVal->value, valueStr);
239     pDVal->initialized = YES;
240     return YES;
241 }
242 
DVal_initialized(const DVal_t * pDVal)243 PUBLIC BOOL DVal_initialized(const DVal_t * pDVal)
244 {
245     return (pDVal->initialized != NO);
246 }
247 
DVal_compare(const DVal_t * a,const DVal_t * b)248 PUBLIC int DVal_compare(const DVal_t * a, const DVal_t * b)
249 {
250     if (a->year > b->year) return 1;
251     if (a->year < b->year) return -1;
252     if (a->month > b->month) return 1;
253     if (a->month < b->month) return -1;
254     if (a->day > b->day) return 1;
255     if (a->day < b->day) return -1;
256     if (a->hour+a->timeZoneHours > b->hour+b->timeZoneHours) return 1;
257     if (a->hour+a->timeZoneHours < b->hour+b->timeZoneHours) return -1;
258     if (a->minute+a->timeZoneMinutes > b->minute+b->timeZoneMinutes) return 1;
259     if (a->minute+a->timeZoneMinutes < b->minute+b->timeZoneMinutes) return -1;
260     return 0;
261 }
262 
DVal_value(const DVal_t * pDVal)263 PUBLIC char * DVal_value(const DVal_t * pDVal)
264 {
265     return (pDVal->value);
266 }
267 
DVal_clear(DVal_t * pDVal)268 PUBLIC void DVal_clear(DVal_t * pDVal)
269 {
270     if (DVal_initialized(pDVal)) {
271         HT_FREE(pDVal->value);
272 	pDVal->initialized = NO;
273     }
274     return;
275 }
276 
Range_toStr(Range_t * pRange)277 PUBLIC char * Range_toStr(Range_t * pRange)
278 {
279     HTChunk * pChunk;
280     char * ptr;
281     pChunk = HTChunk_new(20);
282     ptr = FVal_toStr(&pRange->min);
283     HTChunk_puts(pChunk, ptr);
284     HT_FREE(ptr);
285     if (FVal_initialized(&pRange->max)) {
286         ptr = FVal_toStr(&pRange->max);
287 	HTChunk_puts(pChunk, ":");
288 	HTChunk_puts(pChunk, ptr);
289 	HT_FREE(ptr);
290     }
291     return HTChunk_toCString(pChunk);
292 }
293 
294 /* Range_gap - find gap between 2 ranges. Either of these ranges may be a
295  * single value (in the min)
296  * negative vector indicates that ref is greater than test
297  */
Range_gap(Range_t * a,Range_t * b)298 PUBLIC FVal_t Range_gap(Range_t * a, Range_t * b)
299 {
300     Range_t aN = *a;
301     Range_t bN = *b;
302     FVal_t ret = FVal_NEW_UNINITIALIZED;
303     if (!FVal_initialized(&a->min) || !FVal_initialized(&b->min))
304         return (ret);
305 
306     /* set ret for successful 0 returns */
307     FVal_set(&ret, (float)0.0);
308 
309     /* normalize our ranges */
310     if (FVal_lessThan(&aN.max, &aN.min)) {
311         aN.max = a->min;
312         aN.min = a->max;
313     }
314     if (FVal_lessThan(&bN.max, &bN.min)) {
315         bN.max = b->min;
316         bN.min = b->max;
317     }
318 
319     /* check partial ranges (just a min, no max) */
320     if (!FVal_initialized(&aN.max)) {
321         if (!FVal_initialized(&bN.max))
322             return FVal_minus(&aN.min, &bN.min);
323         if (FVal_lessThan(&aN.min, &bN.min))
324             return FVal_minus(&bN.min, &aN.min);
325         if (FVal_lessThan(&bN.max, &aN.min))
326             return FVal_minus(&bN.max, &aN.min);
327         return ret;
328     }
329     /* we have four values to compare */
330     {
331         FVal_t minDif = FVal_minus(&bN.min, &aN.min);
332         FVal_t maxDif = FVal_minus(&bN.max, &aN.max);
333         Range_t common;
334         common.min = FVal_lessThan(&bN.min, &aN.min) ? aN.min : bN.min;
335         common.max = FVal_lessThan(&bN.max, &aN.max) ? bN.max : aN.max;
336         if (!FVal_lessThan(&common.max, &common.min))
337             return ret;
338         /* failure - indicate how far we are off */
339         return FVal_nearerZero(&minDif, &maxDif) ? minDif : maxDif;
340     }
341 }
342 
343 /* ------------------------------------------------------------------------- */
344 
345 /* C O N S T R U C T O R S */
CSParse_new(void)346 PUBLIC CSParse_t * CSParse_new(void)
347 {
348     CSParse_t * me;
349 	if ((me = (CSParse_t *) HT_CALLOC(1, sizeof(CSParse_t))) == NULL)
350 	    HT_OUTOFMEM("CSParse");
351     me->nowIn = NowIn_NEEDOPEN;
352     me->token = HTChunk_new(0x10);
353 	if ((me->pParseContext = (ParseContext_t *) HT_CALLOC(1, sizeof(ParseContext_t))) == NULL)
354 	    HT_OUTOFMEM("ParseContext_t");
355     return me;
356 }
357 
CSParse_delete(CSParse_t * me)358 PUBLIC void CSParse_delete(CSParse_t * me)
359 {
360 	HT_FREE(me->pParseContext);
361 	HTChunk_delete(me->token);
362 	HT_FREE(me);
363 }
364 
365 /* L A B E L   P A R S E R S */
callErrorHandler(CSParse_t * pCSParse,const char * errorLocation,char demark,StateRet_t errorCode)366 PRIVATE StateRet_t callErrorHandler(CSParse_t * pCSParse,
367 				    const char * errorLocation,
368 				    char demark, StateRet_t errorCode)
369 {
370     char * token = HTChunk_data(pCSParse->token);
371     pCSParse->pParseContext->pTokenError = (char *)  errorLocation;
372     return (*pCSParse->pParseContext->pParseErrorHandler)(pCSParse, token,
373 					      demark, StateRet_ERROR_BAD_CHAR);
374 }
375 
376 /* CSParse_parseChunk - elemental parse engine for all pics nowIns. This passes
377  * tokenized data into the handler functions in the CSParse_t.handlersOf. These
378  * handlers are responsibel for placing the data in the appropriate target.
379  * The text is broken into nowIns and passed a SubParser based on the current
380  * nowIn which is one of:
381  *  NowIn_NEEDOPEN - get paren and go to NowIn_ENGINE, text is an error
382  *  NowIn_ENGINE - in a containing structure, text goes to engineOf_
383  *  NowIn_NEEDCLOSE - get paren and go to NowIn_ENGINE, text is an error
384  *  NowIn_END - expect no more text or parens
385  *  NowIn_ERROR -
386  */
CSParse_parseChunk(CSParse_t * pCSParse,const char * ptr,int len,void * pVoid)387 PUBLIC CSDoMore_t CSParse_parseChunk (CSParse_t * pCSParse, const char * ptr, int len, void * pVoid)
388 {
389     int i;
390     if (!len || !ptr)
391         return CSDoMore_error;
392     for (i = 0; i < len; i++) {
393         pCSParse->offset++;
394         if (pCSParse->quoteState) {
395             if (pCSParse->quoteState == ptr[i]) {
396                 pCSParse->quoteState = 0;
397                 pCSParse->demark = ' ';
398             }
399             else
400                 HTChunk_putb(pCSParse->token, ptr+i, 1);
401             continue;
402         }
403         if (ptr[i] == SQUOTE || ptr[i] == DQUOTE) {
404             if (pCSParse->demark) {
405                 while ((pCSParse->nowIn = (*pCSParse->pParseContext->engineOf)(pCSParse, ' ', pVoid)) == NowIn_CHAIN);
406                 HTChunk_clear(pCSParse->token);
407                 pCSParse->demark = 0;
408             } else if (HTChunk_size(pCSParse->token) &&
409 /*                  && warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) */
410 		       callErrorHandler(pCSParse, ptr+i, ptr[i],
411 					StateRet_ERROR_BAD_CHAR) !=StateRet_OK)
412 		    pCSParse->nowIn = NowIn_ERROR;
413             pCSParse->quoteState = ptr[i];
414             pCSParse->pParseContext->observedQuotes = YES;
415             continue;
416         }
417         switch (pCSParse->nowIn) {
418             case NowIn_NEEDOPEN:
419                 if (ptr[i] == LPAREN) {
420                     pCSParse->nowIn = NowIn_ENGINE;
421                     continue;
422                 }
423                 if (isspace((int) ptr[i]))
424                     continue;
425 /*                if (warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) pCSParse->nowIn = NowIn_ERROR; */
426 	        if (callErrorHandler(pCSParse, ptr+i, ptr[i],
427 				     StateRet_ERROR_BAD_CHAR) !=StateRet_OK)
428 		    pCSParse->nowIn = NowIn_ERROR;
429                 continue;
430             case NowIn_ENGINE:
431                 if (isspace((int) ptr[i])) {
432                     if (HTChunk_size(pCSParse->token))
433                         pCSParse->demark = ' ';
434                     continue;
435                 }
436                 if (ptr[i] == LPAREN || ptr[i] == RPAREN || pCSParse->demark) {
437 		    /* parens override space demarkation */
438 		    if (ptr[i] == LPAREN) pCSParse->demark = LPAREN;
439 		    if (ptr[i] == RPAREN) pCSParse->demark = RPAREN;
440 		    /* call the engine as long as it wants re-entrance */
441                     while ((pCSParse->nowIn = (*pCSParse->pParseContext->engineOf)(pCSParse, pCSParse->demark, pVoid)) == NowIn_CHAIN);
442                     HTChunk_clear(pCSParse->token);
443                     pCSParse->demark = 0;
444                     if (ptr[i] == LPAREN || ptr[i] == RPAREN)
445                         continue;
446                     /* continue with next token */
447                 }
448                 HTChunk_putb(pCSParse->token, ptr+i, 1);
449                 continue;
450             case NowIn_NEEDCLOSE:
451                 if (ptr[i] == RPAREN) {
452                     pCSParse->nowIn = NowIn_ENGINE;
453                     continue;
454                 }
455                 if (isspace((int) ptr[i]))
456                     continue;
457 		if (callErrorHandler(pCSParse, ptr+i, ptr[i],
458 				     StateRet_ERROR_BAD_CHAR) !=StateRet_OK)
459 		    pCSParse->nowIn = NowIn_ERROR;
460 /*                if (warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) pCSParse->nowIn = NowIn_ERROR; */
461                 continue;
462             case NowIn_END:
463 #if 0 /* enable this to tell the parser to check the remainder of
464 		 the stream after the parsed object thinks it is done */
465                 if (isspace(ptr[i]))
466                     continue;
467 /*                if (warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) pCSParse->nowIn = NowIn_ERROR; */
468 		if (callErrorHandler(pCSParse, ptr+i, ptr[i],
469 				     StateRet_ERROR_BAD_CHAR) !=StateRet_OK)
470 		    pCSParse->nowIn = NowIn_ERROR;
471                 continue;
472 #else
473                 return CSDoMore_done;
474 #endif
475             case NowIn_MATCHCLOSE:
476                 if (ptr[i] == RPAREN) {
477                     if (!pCSParse->depth)
478                         pCSParse->nowIn = NowIn_ENGINE;
479                     else
480                         pCSParse->depth--;
481                 }
482                 if (ptr[i] == LPAREN)
483                     pCSParse->depth++;
484                 continue;
485             case NowIn_ERROR:
486                 return CSDoMore_error;
487                 break;
488             default:
489 		HTTRACE(PICS_TRACE, "PICS: Internal error in parser - bad nowIn:%d.\n" _
490 			pCSParse->nowIn);
491 		return CSDoMore_error;
492         }
493     }
494     /* check completion */
495     return pCSParse->nowIn == NowIn_END ? CSDoMore_done : CSDoMore_more;
496 }
497 
Punct_badDemark(Punct_t validPunctuation,char demark)498 PUBLIC BOOL Punct_badDemark(Punct_t validPunctuation, char demark)
499 {
500     switch (demark) {
501 		case ' ': return (!(validPunctuation & Punct_WHITE));
502 		case LPAREN: return (!(validPunctuation & Punct_LPAREN));
503 		case RPAREN: return (!(validPunctuation & Punct_RPAREN));
504 	}
505     return YES;
506 }
507 
CSParse_subState2str(SubState_t subState)508 PUBLIC char * CSParse_subState2str(SubState_t subState)
509 {
510     static char space[33];
511     space[0] = 0;
512     if (subState == SubState_N)
513         strcpy(space, "N");
514     else if (subState == SubState_X)
515         strcpy(space, "X");
516     else {
517         int i;
518 	SubState_t comp;
519 	char ch[] = "A";
520 	for (i = 1, comp = SubState_A; i < (sizeof(SubState_t)*8 - 1); i++, (*ch)++, comp<<=1)
521 	    if (comp & subState)
522 	        strcat(space, ch);
523     }
524     return space;
525 }
526 
ParseTrace(const char * fmt,...)527 PRIVATE int ParseTrace(const char * fmt, ...)
528 {
529     va_list pArgs;
530     va_start(pArgs, fmt);
531     if (!ParseDebug)
532         return 0;
533     return (vfprintf(stderr, fmt, pArgs));
534 }
535 
CSParse_targetParser(CSParse_t * pCSParse,char demark,void * pVoid)536 PUBLIC NowIn_t CSParse_targetParser(CSParse_t * pCSParse, char demark, void * pVoid)
537 {
538 /*    ParseContext_t * pParseContext = pCSParse->pParseContext; */
539     TargetObject_t * pTargetObject = pCSParse->pTargetObject;
540     BOOL failedOnPunct = NO;
541     char * token = 0;
542     StateRet_t ret = StateRet_OK;
543     int i;
544 static NowIn_t lastRet = NowIn_END;
545 
546     if (HTChunk_size(pCSParse->token)) {
547         HTChunk_terminate(pCSParse->token);
548         token = HTChunk_data(pCSParse->token);
549     }
550     for (i = 0; i < pTargetObject->stateTokenCount; i++) {
551         StateToken_t * pStateToken = pTargetObject->stateTokens + i;
552         pCSParse->pStateToken = pStateToken;
553 
554         if (!(pCSParse->currentSubState & pStateToken->validSubStates))
555             continue;
556         if (pStateToken->pCheck) {  /* use check function */
557             StateRet_t checkRes;
558             checkRes = (*pStateToken->pCheck)(pCSParse, pStateToken, token, demark);
559             switch (checkRes) {
560                 case StateRet_WARN_BAD_PUNCT:
561                     failedOnPunct = YES;
562                 case StateRet_WARN_NO_MATCH:
563                     continue;
564                 case StateRet_ERROR_BAD_CHAR:
565 		    (*pCSParse->pParseContext->pParseErrorHandler)(pCSParse, token, demark, StateRet_ERROR_BAD_CHAR);
566 		    /*                    if (pTargetObject->pDestroy)
567 		        (*pTargetObject->pDestroy)(pCSParse); */
568                     return NowIn_ERROR;
569 	        default:
570 		    break;
571             }
572         } else {                    /* or match by name[s] */
573             if (!(pStateToken->command & Command_MATCHANY)) {
574 	        if (token && pStateToken->name1) {
575         	    if (strcasecomp(token, pStateToken->name1) && (!pStateToken->name2 || strcasecomp(token, pStateToken->name2)))
576        		        continue;
577 	        } else {
578 		    if (token != pStateToken->name1)
579 	                continue;
580 	        }
581 	    }
582             if (Punct_badDemark(pStateToken->validPunctuation, demark)) {
583                 failedOnPunct = YES;
584                 continue;
585             }
586         }
587 /* open or close and do the appropriate callbacks */
588 	if (lastRet != NowIn_CHAIN)
589 	    ParseTrace("%30s %c ", token ? token : "", demark);
590         ParseTrace("%10s - %s:%10s => ", pCSParse->pTargetObject->note, CSParse_subState2str(pCSParse->currentSubState), pStateToken->note);
591 	if (pStateToken->command & Command_NOTOKEN) {
592 	    HTChunk_clear(pCSParse->token);
593 		token = 0;
594 	}
595 	if (pStateToken->command & Command_OPEN && pTargetObject->pOpen)
596 	    if ((*pTargetObject->pOpen)(pCSParse, token, demark) == StateRet_ERROR)
597 		return NowIn_ERROR;
598         if (pStateToken->command & (Command_OPEN|Command_CLOSE) && pCSParse->pParseContext->pTargetChangeCallback) {
599 	    ParseTrace("%3d", pStateToken->command & Command_CLOSE ? -pTargetObject->targetChange : pTargetObject->targetChange);
600 	    if ((*pCSParse->pParseContext->pTargetChangeCallback)(pCSParse, pTargetObject, pTargetObject->targetChange,
601 		(BOOL)(pStateToken->command & Command_CLOSE), pVoid) == StateRet_ERROR)
602 		return NowIn_ERROR;
603 	} else
604 	    ParseTrace("   ");
605         if (pStateToken->command & Command_CLOSE && pTargetObject->pClose)
606             ret = (*pTargetObject->pClose)(pCSParse, token, demark);
607 
608         if (pStateToken->pPrep && ret != NowIn_ERROR)
609             ret = (*pStateToken->pPrep)(pCSParse, token, demark);
610         if (pStateToken->pNextTargetObject)
611             pCSParse->pTargetObject = pStateToken->pNextTargetObject;
612         if (pStateToken->nextSubState != SubState_X)
613             pCSParse->currentSubState = pStateToken->nextSubState;
614         ParseTrace("%10s - %s", pCSParse->pTargetObject->note, CSParse_subState2str(pCSParse->currentSubState));
615         if (pStateToken->command & Command_CHAIN) {
616 	    ParseTrace(" -O-O-");
617             return lastRet = NowIn_CHAIN;
618 	}
619 	ParseTrace("\n");
620         return lastRet = ret == StateRet_ERROR_BAD_CHAR ? NowIn_ERROR : ret == StateRet_DONE ? NowIn_END : NowIn_ENGINE;
621     }
622     (*pCSParse->pParseContext->pParseErrorHandler)(pCSParse, token, demark, failedOnPunct ? StateRet_WARN_BAD_PUNCT : StateRet_WARN_NO_MATCH);
623     if (pTargetObject->pDestroy)
624 	    (*pTargetObject->pDestroy)(pCSParse);
625     return NowIn_ERROR;
626 }
627 
628