Annotation of libwww/Library/src/SGML.c, revision 1.14

1.1       timbl       1: /*                     General SGML Parser code                SGML.c
                      2: **                     ========================
                      3: **
1.2       timbl       4: **     This module implements an HTStream object. To parse an
1.1       timbl       5: **     SGML file, create this object which is a parser. The object
1.2       timbl       6: **     is (currently) created by being passed a DTD structure,
                      7: **     and a target HTStructured oject at which to throw the parsed stuff.
1.1       timbl       8: **     
1.2       timbl       9: **      6 Feb 93  Binary seraches used. Intreface modified.
1.1       timbl      10: */
                     11: #include "SGML.h"
                     12: 
                     13: #include <ctype.h>
                     14: #include <stdio.h>
                     15: #include "HTUtils.h"
                     16: #include "HTChunk.h"
                     17: #include "tcp.h"               /* For FROMASCII */
                     18: 
1.2       timbl      19: #define INVALID (-1)
                     20: 
1.1       timbl      21: /*     The State (context) of the parser
                     22: **
1.2       timbl      23: **     This is passed with each call to make the parser reentrant
1.1       timbl      24: **
                     25: */
                     26: 
1.2       timbl      27: #define MAX_ATTRIBUTES 20      /* Max number of attributes per element */
                     28: 
                     29:        
                     30: /*             Element Stack
                     31: **             -------------
                     32: **     This allows us to return down the stack reselcting styles.
                     33: **     As we return, attribute values will be garbage in general.
                     34: */
                     35: typedef struct _HTElement HTElement;
                     36: struct _HTElement {
                     37:        HTElement *     next;   /* Previously nested element or 0 */
                     38:        HTTag*          tag;    /* The tag at this level  */
                     39: };
                     40: 
                     41: 
                     42: /*     Internal Context Data Structure
                     43: **     -------------------------------
                     44: */
                     45: struct _HTStream {
                     46: 
                     47:     CONST HTStreamClass *      isa;            /* inherited from HTStream */
                     48:     
                     49:     CONST SGML_dtd             *dtd;
                     50:     HTStructuredClass  *actions;       /* target class  */
                     51:     HTStructured       *target;        /* target object */
                     52: 
1.1       timbl      53:     HTTag              *current_tag;
1.2       timbl      54:     int                current_attribute_number;
1.1       timbl      55:     HTChunk            *string;
                     56:     HTElement          *element_stack;
1.12      timbl      57:     enum sgml_state { S_text, S_literal, S_tag, S_tag_gap, 
1.1       timbl      58:                S_attr, S_attr_gap, S_equals, S_value,
                     59:                S_ero, S_cro,
1.13      timbl      60: #ifdef ISO_2022_JP
                     61:                S_esc, S_dollar, S_paren, S_nonascii_text,
                     62: #endif
1.1       timbl      63:                  S_squoted, S_dquoted, S_end, S_entity, S_junk_tag} state;
1.2       timbl      64: #ifdef CALLERDATA                
1.1       timbl      65:     void *             callerData;
1.2       timbl      66: #endif
                     67:     BOOL present[MAX_ATTRIBUTES];      /* Flags: attribute is present? */
                     68:     char * value[MAX_ATTRIBUTES];      /* malloc'd strings or NULL if none */
                     69: } ;
                     70: 
                     71: 
                     72: #define PUTC(ch) ((*context->actions->put_character)(context->target, ch))
                     73: 
1.1       timbl      74: 
                     75: 
                     76: /*     Handle Attribute
                     77: **     ----------------
                     78: */
                     79: /* PUBLIC CONST char * SGML_default = "";   ?? */
                     80: 
                     81: #ifdef __STDC__
1.2       timbl      82: PRIVATE void handle_attribute_name(HTStream * context, const char * s)
1.1       timbl      83: #else
                     84: PRIVATE void handle_attribute_name(context, s)
1.2       timbl      85:     HTStream * context;
1.1       timbl      86:     char *s;
                     87: #endif
                     88: {
1.2       timbl      89: 
                     90:     HTTag * tag = context->current_tag;
                     91:     attr* attributes = tag->attributes;
                     92: 
                     93:     int high, low, i, diff;            /* Binary search for attribute name */
                     94:     for(low=0, high=tag->number_of_attributes;
                     95:                high > low ;
                     96:                diff < 0 ? (low = i+1) : (high = i) )  {
                     97:        i = (low + (high-low)/2);
                     98:        diff = strcasecomp(attributes[i].name, s);
                     99:        if (diff==0) {                  /* success: found it */
                    100:            context->current_attribute_number = i;
                    101:            context->present[i] = YES;
                    102:            if (context->value[i]) {
                    103:                free(context->value[i]);
                    104:                context->value[i] = NULL;
                    105:            }
                    106:            return;
                    107:        } /* if */
                    108:        
                    109:     } /* for */
                    110:     
                    111:     if (TRACE)
                    112:        fprintf(stderr, "SGML: Unknown attribute %s for tag %s\n",
                    113:            s, context->current_tag->name);
                    114:     context->current_attribute_number = INVALID;       /* Invalid */
1.1       timbl     115: }
                    116: 
                    117: 
                    118: /*     Handle attribute value
                    119: **     ----------------------
                    120: */
                    121: #ifdef __STDC__
1.2       timbl     122: PRIVATE void handle_attribute_value(HTStream * context, const char * s)
1.1       timbl     123: #else
                    124: PRIVATE void handle_attribute_value(context, s)
1.2       timbl     125:     HTStream * context;
1.1       timbl     126:     char *s;
                    127: #endif
                    128: {
1.2       timbl     129:     if (context->current_attribute_number != INVALID) {
                    130:        StrAllocCopy(context->value[context->current_attribute_number], s);
1.1       timbl     131:     } else {
                    132:         if (TRACE) fprintf(stderr, "SGML: Attribute value %s ignored\n", s);
                    133:     }
1.2       timbl     134:     context->current_attribute_number = INVALID; /* can't have two assignments! */
1.1       timbl     135: }
                    136: 
1.2       timbl     137: 
1.1       timbl     138: /*     Handle entity
                    139: **     -------------
                    140: **
                    141: ** On entry,
                    142: **     s       contains the entity name zero terminated
                    143: ** Bugs:
                    144: **     If the entity name is unknown, the terminator is treated as
                    145: **     a printable non-special character in all cases, even if it is '<'
                    146: */
                    147: #ifdef __STDC__
1.2       timbl     148: PRIVATE void handle_entity(HTStream * context, char term)
1.1       timbl     149: #else
                    150: PRIVATE void handle_entity(context, term)
1.2       timbl     151:     HTStream * context;
1.1       timbl     152:     char term;
                    153: #endif
                    154: {
1.2       timbl     155: 
1.3       timbl     156:     CONST char ** entities = context->dtd->entity_names;
1.1       timbl     157:     CONST char *s = context->string->data;
1.2       timbl     158:     
                    159:     int high, low, i, diff;
                    160:     for(low=0, high = context->dtd->number_of_entities;
                    161:                high > low ;
                    162:                diff < 0 ? (low = i+1) : (high = i))   {  /* Binary serach */
                    163:        i = (low + (high-low)/2);
                    164:        diff = strcmp(entities[i], s);  /* Csse sensitive! */
                    165:        if (diff==0) {                  /* success: found it */
                    166:            (*context->actions->put_entity)(context->target, i);
                    167:            return;
1.1       timbl     168:        }
                    169:     }
                    170:     /* If entity string not found, display as text */
                    171:     if (TRACE)
                    172:        fprintf(stderr, "SGML: Unknown entity %s\n", s); 
1.2       timbl     173:     PUTC('&');
1.1       timbl     174:     {
                    175:        CONST char *p;
                    176:        for (p=s; *p; p++) {
1.2       timbl     177:            PUTC(*p);
1.1       timbl     178:        }
                    179:     }
1.2       timbl     180:     PUTC(term);
1.1       timbl     181: }
                    182: 
1.2       timbl     183: 
1.1       timbl     184: /*     End element
1.2       timbl     185: **     -----------
1.1       timbl     186: */
                    187: #ifdef __STDC__
1.2       timbl     188: PRIVATE void end_element(HTStream * context, HTTag * old_tag)
1.1       timbl     189: #else
                    190: PRIVATE void end_element(context, old_tag)
                    191:     HTTag * old_tag;
1.2       timbl     192:     HTStream * context;
1.1       timbl     193: #endif
                    194: {
                    195:     if (TRACE) fprintf(stderr, "SGML: End   </%s>\n", old_tag->name);
1.2       timbl     196:     if (old_tag->contents == SGML_EMPTY) {
1.1       timbl     197:         if (TRACE) fprintf(stderr,"SGML: Illegal end tag </%s> found.\n",
                    198:                old_tag->name);
                    199:        return;
                    200:     }
                    201:     while (context->element_stack)     {/* Loop is error path only */
                    202:        HTElement * N = context->element_stack;
                    203:        HTTag * t = N->tag;
                    204:        
                    205:        if (old_tag != t) {             /* Mismatch: syntax error */
                    206:            if (context->element_stack->next) { /* This is not the last level */
                    207:                if (TRACE) fprintf(stderr,
                    208:                "SGML: Found </%s> when expecting </%s>. </%s> assumed.\n",
                    209:                    old_tag->name, t->name, t->name);
                    210:            } else {                    /* last level */
                    211:                if (TRACE) fprintf(stderr,
                    212:                    "SGML: Found </%s> when expecting </%s>. </%s> Ignored.\n",
                    213:                    old_tag->name, t->name, old_tag->name);
                    214:                return;                 /* Ignore */
                    215:            }
                    216:        }
                    217:        
                    218:        context->element_stack = N->next;               /* Remove from stack */
                    219:        free(N);
1.2       timbl     220:        (*context->actions->end_element)(context->target,
                    221:                 t - context->dtd->tags);
1.1       timbl     222:        if (old_tag == t) return;  /* Correct sequence */
                    223:        
                    224:        /* Syntax error path only */
                    225:        
                    226:     }
1.5       timbl     227:     if (TRACE) fprintf(stderr,
1.1       timbl     228:        "SGML: Extra end tag </%s> found and ignored.\n", old_tag->name);
                    229: }
                    230: 
                    231: 
                    232: /*     Start a element
                    233: */
                    234: #ifdef __STDC__
1.2       timbl     235: PRIVATE void start_element(HTStream * context)
1.1       timbl     236: #else
                    237: PRIVATE void start_element(context)
1.2       timbl     238:     HTStream * context;
1.1       timbl     239: #endif
                    240: {
                    241:     HTTag * new_tag = context->current_tag;
                    242:     
                    243:     if (TRACE) fprintf(stderr, "SGML: Start <%s>\n", new_tag->name);
1.2       timbl     244:     (*context->actions->start_element)(
                    245:        context->target,
                    246:        new_tag - context->dtd->tags,
                    247:        context->present,
1.3       timbl     248:        (CONST char**) context->value);  /* coerce type for think c */
1.2       timbl     249:     if (new_tag->contents != SGML_EMPTY) {             /* i.e. tag not empty */
1.1       timbl     250:        HTElement * N = (HTElement *)malloc(sizeof(HTElement));
                    251:         if (N == NULL) outofmem(__FILE__, "start_element");
                    252:        N->next = context->element_stack;
                    253:        N->tag = new_tag;
                    254:        context->element_stack = N;
                    255:     }
                    256: }
                    257: 
                    258: 
1.2       timbl     259: /*             Find Tag in DTD tag list
                    260: **             ------------------------
1.1       timbl     261: **
                    262: ** On entry,
1.2       timbl     263: **     dtd     points to dtd structire including valid tag list
                    264: **     string  points to name of tag in question
1.1       timbl     265: **
1.2       timbl     266: ** On exit,
                    267: **     returns:
1.7       timbl     268: **             NULL            tag not found
                    269: **             else            address of tag structure in dtd
1.2       timbl     270: */
1.11      timbl     271: PUBLIC HTTag * SGMLFindTag ARGS2(CONST SGML_dtd*, dtd, CONST char *, string)
1.2       timbl     272: {
                    273:     int high, low, i, diff;
                    274:     for(low=0, high=dtd->number_of_tags;
                    275:                high > low ;
                    276:                diff < 0 ? (low = i+1) : (high = i))   {  /* Binary serach */
                    277:        i = (low + (high-low)/2);
1.3       timbl     278:        diff = strcasecomp(dtd->tags[i].name, string);  /* Case insensitive */
1.2       timbl     279:        if (diff==0) {                  /* success: found it */
1.7       timbl     280:            return &dtd->tags[i];
1.2       timbl     281:        }
                    282:     }
1.7       timbl     283:     return NULL;
1.2       timbl     284: }
                    285: 
                    286: /*________________________________________________________________________
                    287: **                     Public Methods
1.1       timbl     288: */
                    289: 
1.2       timbl     290: 
                    291: /*     Could check that we are back to bottom of stack! @@  */
1.1       timbl     292: 
1.8       timbl     293: PUBLIC void SGML_free  ARGS1(HTStream *, context)
                    294: {
1.14    ! frystyk   295:     int cnt;
        !           296: 
1.8       timbl     297:     (*context->actions->free)(context->target);
                    298:     HTChunkFree(context->string);
1.14    ! frystyk   299:     for(cnt=0; cnt<MAX_ATTRIBUTES; cnt++)              /* Leak fix Henrik 18/02-94 */
        !           300:        if(context->value[cnt])
        !           301:            free(context->value[cnt]);
1.8       timbl     302:     free(context);
1.1       timbl     303: }
                    304: 
1.8       timbl     305: PUBLIC void SGML_abort  ARGS2(HTStream *, context, HTError, e)
1.1       timbl     306: {
1.14    ! frystyk   307:     int cnt;
        !           308: 
1.8       timbl     309:     (*context->actions->abort)(context->target, e);
1.1       timbl     310:     HTChunkFree(context->string);
1.14    ! frystyk   311:     for(cnt=0; cnt<MAX_ATTRIBUTES; cnt++)              /* Leak fix Henrik 18/02-94 */
        !           312:        if(context->value[cnt])
        !           313:            free(context->value[cnt]);
1.1       timbl     314:     free(context);
                    315: }
                    316: 
1.2       timbl     317: 
1.1       timbl     318: /*     Read and write user callback handle
                    319: **     -----------------------------------
                    320: **
                    321: **   The callbacks from the SGML parser have an SGML context parameter.
                    322: **   These calls allow the caller to associate his own context with a
                    323: **   particular SGML context.
                    324: */
                    325: 
1.2       timbl     326: #ifdef CALLERDATA                
                    327: PUBLIC void* SGML_callerData ARGS1(HTStream *, context)
1.1       timbl     328: {
                    329:     return context->callerData;
                    330: }
                    331: 
1.2       timbl     332: PUBLIC void SGML_setCallerData ARGS2(HTStream *, context, void*, data)
1.1       timbl     333: {
                    334:     context->callerData = data;
                    335: }
1.2       timbl     336: #endif
1.1       timbl     337: 
1.2       timbl     338: PUBLIC void SGML_character ARGS2(HTStream *, context, char,c)
1.1       timbl     339: 
                    340: {
1.2       timbl     341:     CONST SGML_dtd     *dtd    =       context->dtd;
1.1       timbl     342:     HTChunk    *string =       context->string;
                    343: 
                    344:     switch(context->state) {
                    345:     case S_text:
1.13      timbl     346: #ifdef ISO_2022_JP
                    347:        if (c=='\033') {
                    348:            context->state = S_esc;
                    349:            PUTC(c);
                    350:            break;
                    351:        }
                    352: #endif /* ISO_2022_JP */
1.6       timbl     353:        if (c=='&' && (!context->element_stack || (
                    354:                         context->element_stack->tag  &&
                    355:                         ( context->element_stack->tag->contents == SGML_MIXED
                    356:                           || context->element_stack->tag->contents ==
                    357:                                                         SGML_RCDATA)
                    358:                        ))) {
1.1       timbl     359:            string->size = 0;
                    360:            context->state = S_ero;
                    361:            
                    362:        } else if (c=='<') {
                    363:            string->size = 0;
                    364:            context->state = (context->element_stack &&
1.13      timbl     365:                context->element_stack->tag  &&
                    366:                context->element_stack->tag->contents == SGML_LITERAL) ?
1.12      timbl     367:                                S_literal : S_tag;
1.2       timbl     368:        } else PUTC(c);
1.1       timbl     369:        break;
1.13      timbl     370: 
                    371: #ifdef ISO_2022_JP
                    372:     case S_esc:
                    373:        if (c=='$') {
                    374:            context->state = S_dollar;
                    375:        } else if (c=='(') {
                    376:            context->state = S_paren;
                    377:        } else {
                    378:            context->state = S_text;
                    379:        }
                    380:        PUTC(c);
                    381:        break;
                    382:     case S_dollar:
                    383:        if (c=='@' || c=='B') {
                    384:            context->state = S_nonascii_text;
                    385:        } else {
                    386:            context->state = S_text;
                    387:        }
                    388:        PUTC(c);
                    389:        break;
                    390:     case S_paren:
                    391:        if (c=='B' || c=='J') {
                    392:            context->state = S_text;
                    393:        } else {
                    394:            context->state = S_text;
                    395:        }
                    396:        PUTC(c);
                    397:        break;
                    398:     case S_nonascii_text:
                    399:        if (c=='\033') {
                    400:            context->state = S_esc;
                    401:            PUTC(c);
                    402:        } else {
                    403:            PUTC(c);
                    404:        }
                    405:        break;
                    406: #endif /* ISO_2022_JP */
1.1       timbl     407: 
1.12      timbl     408: /*     In literal mode, waits only for specific end tag!
1.2       timbl     409: **     Only foir compatibility with old servers.
1.1       timbl     410: */
1.12      timbl     411:     case S_literal :
1.1       timbl     412:        HTChunkPutc(string, c);
                    413:        if ( TOUPPER(c) != ((string->size ==1) ? '/'
                    414:                : context->element_stack->tag->name[string->size-2])) {
                    415:            int i;
                    416:            
1.12      timbl     417:            /*  If complete match, end literal */
1.1       timbl     418:            if ((c=='>') && (!context->element_stack->tag->name[string->size-2])) {
                    419:                end_element(context, context->element_stack->tag);
                    420:                string->size = 0;
1.2       timbl     421:                context->current_attribute_number = INVALID;
1.1       timbl     422:                context->state = S_text;
                    423:                break;
                    424:            }           /* If Mismatch: recover string. */
1.2       timbl     425:            PUTC( '<');
1.1       timbl     426:            for (i=0; i<string->size; i++)      /* recover */
1.2       timbl     427:               PUTC(
1.1       timbl     428:                                              string->data[i]);
                    429:            context->state = S_text;    
                    430:        }
                    431:        
                    432:         break;
                    433: 
                    434: /*     Character reference or Entity
                    435: */
                    436:    case S_ero:
                    437:        if (c=='#') {
                    438:            context->state = S_cro;  /*   &# is Char Ref Open */ 
                    439:            break;
                    440:        }
                    441:        context->state = S_entity;    /* Fall through! */
                    442:        
                    443: /*     Handle Entities
                    444: */
                    445:     case S_entity:
                    446:        if (isalnum(c))
                    447:            HTChunkPutc(string, c);
                    448:        else {
                    449:            HTChunkTerminate(string);
                    450:            handle_entity(context, c);
                    451:            context->state = S_text;
                    452:        }
                    453:        break;
                    454: 
                    455: /*     Character reference
                    456: */
                    457:     case S_cro:
                    458:        if (isalnum(c))
                    459:            HTChunkPutc(string, c);     /* accumulate a character NUMBER */
                    460:        else {
                    461:            int value;
                    462:            HTChunkTerminate(string);
                    463:            if (sscanf(string->data, "%d", &value)==1)
1.2       timbl     464:                PUTC(FROMASCII((char)value));
1.1       timbl     465:            context->state = S_text;
                    466:        }
                    467:        break;
                    468: 
                    469: /*             Tag
                    470: */         
                    471:     case S_tag:                                /* new tag */
                    472:        if (isalnum(c))
                    473:            HTChunkPutc(string, c);
                    474:        else {                          /* End of tag name */
1.7       timbl     475:            HTTag * t;
1.1       timbl     476:            if (c=='/') {
                    477:                if (TRACE) if (string->size!=0)
                    478:                    fprintf(stderr,"SGML:  `<%s/' found!\n", string->data);
                    479:                context->state = S_end;
                    480:                break;
                    481:            }
                    482:            HTChunkTerminate(string) ;
1.2       timbl     483: 
1.10      timbl     484:            t = SGMLFindTag(dtd, string->data);
1.7       timbl     485:            if (!t) {
1.2       timbl     486:                if(TRACE) fprintf(stderr, "SGML: *** Unknown element %s\n",
1.1       timbl     487:                        string->data);
                    488:                context->state = (c=='>') ? S_text : S_junk_tag;
                    489:                break;
                    490:            }
1.7       timbl     491:            context->current_tag = t;
1.2       timbl     492:            
                    493:            /*  Clear out attributes
                    494:            */
1.1       timbl     495:            
1.2       timbl     496:            {
                    497:                int i;
                    498:                for (i=0; i< context->current_tag->number_of_attributes; i++)
                    499:                    context->present[i] = NO;
1.1       timbl     500:            }
                    501:            string->size = 0;
1.2       timbl     502:            context->current_attribute_number = INVALID;
1.1       timbl     503:            
                    504:            if (c=='>') {
                    505:                if (context->current_tag->name) start_element(context);
                    506:                context->state = S_text;
                    507:            } else {
                    508:                context->state = S_tag_gap;
                    509:            }
                    510:        }
                    511:        break;
                    512: 
                    513:                
                    514:     case S_tag_gap:            /* Expecting attribute or > */
                    515:        if (WHITE(c)) break;    /* Gap between attributes */
                    516:        if (c=='>') {           /* End of tag */
                    517:            if (context->current_tag->name) start_element(context);
                    518:            context->state = S_text;
                    519:            break;
                    520:        }
                    521:        HTChunkPutc(string, c);
                    522:        context->state = S_attr;                /* Get attribute */
                    523:        break;
                    524:        
                    525:                                /* accumulating value */
                    526:     case S_attr:
                    527:        if (WHITE(c) || (c=='>') || (c=='=')) {         /* End of word */
                    528:            HTChunkTerminate(string) ;
                    529:            handle_attribute_name(context, string->data);
                    530:            string->size = 0;
                    531:            if (c=='>') {               /* End of tag */
                    532:                if (context->current_tag->name) start_element(context);
                    533:                context->state = S_text;
                    534:                break;
                    535:            }
                    536:            context->state = (c=='=' ?  S_equals: S_attr_gap);
                    537:        } else {
                    538:            HTChunkPutc(string, c);
                    539:        }
                    540:        break;
                    541:                
                    542:     case S_attr_gap:           /* Expecting attribute or = or > */
                    543:        if (WHITE(c)) break;    /* Gap after attribute */
                    544:        if (c=='>') {           /* End of tag */
                    545:            if (context->current_tag->name) start_element(context);
                    546:            context->state = S_text;
                    547:            break;
                    548:        } else if (c=='=') {
                    549:            context->state = S_equals;
                    550:            break;
                    551:        }
                    552:        HTChunkPutc(string, c);
                    553:        context->state = S_attr;                /* Get next attribute */
                    554:        break;
                    555:        
                    556:     case S_equals:                     /* After attr = */ 
                    557:        if (WHITE(c)) break;    /* Before attribute value */
                    558:        if (c=='>') {           /* End of tag */
1.5       timbl     559:            if (TRACE) fprintf(stderr, "SGML: found = but no value\n");
1.1       timbl     560:            if (context->current_tag->name) start_element(context);
                    561:            context->state = S_text;
                    562:            break;
                    563:            
                    564:        } else if (c=='\'') {
                    565:            context->state = S_squoted;
                    566:            break;
                    567: 
                    568:        } else if (c=='"') {
                    569:            context->state = S_dquoted;
                    570:            break;
                    571:        }
                    572:        HTChunkPutc(string, c);
                    573:        context->state = S_value;
                    574:        break;
                    575:        
                    576:     case S_value:
                    577:        if (WHITE(c) || (c=='>')) {             /* End of word */
                    578:            HTChunkTerminate(string) ;
                    579:            handle_attribute_value(context, string->data);
                    580:            string->size = 0;
                    581:            if (c=='>') {               /* End of tag */
                    582:                if (context->current_tag->name) start_element(context);
                    583:                context->state = S_text;
                    584:                break;
                    585:            }
                    586:            else context->state = S_tag_gap;
                    587:        } else {
                    588:            HTChunkPutc(string, c);
                    589:        }
                    590:        break;
                    591:                
                    592:     case S_squoted:            /* Quoted attribute value */
                    593:        if (c=='\'') {          /* End of attribute value */
                    594:            HTChunkTerminate(string) ;
                    595:            handle_attribute_value(context, string->data);
                    596:            string->size = 0;
                    597:            context->state = S_tag_gap;
                    598:        } else {
                    599:            HTChunkPutc(string, c);
                    600:        }
                    601:        break;
                    602:        
                    603:     case S_dquoted:            /* Quoted attribute value */
                    604:        if (c=='"') {           /* End of attribute value */
                    605:            HTChunkTerminate(string) ;
                    606:            handle_attribute_value(context, string->data);
                    607:            string->size = 0;
                    608:            context->state = S_tag_gap;
                    609:        } else {
                    610:            HTChunkPutc(string, c);
                    611:        }
                    612:        break;
                    613:        
                    614:     case S_end:                                        /* </ */
                    615:        if (isalnum(c))
                    616:            HTChunkPutc(string, c);
                    617:        else {                          /* End of end tag name */
1.7       timbl     618:            HTTag * t;
1.1       timbl     619:            HTChunkTerminate(string) ;
1.7       timbl     620:            if (!*string->data) {       /* Empty end tag */
                    621:                t = context->element_stack->tag;
                    622:            } else {
1.10      timbl     623:                t = SGMLFindTag(dtd, string->data);
1.1       timbl     624:            }
1.7       timbl     625:            if (!t) {
1.1       timbl     626:                if(TRACE) fprintf(stderr,
                    627:                    "Unknown end tag </%s>\n", string->data); 
1.2       timbl     628:            } else {
1.7       timbl     629:                context->current_tag = t;
1.2       timbl     630:                end_element( context, context->current_tag);
1.1       timbl     631:            }
1.2       timbl     632: 
1.1       timbl     633:            string->size = 0;
1.2       timbl     634:            context->current_attribute_number = INVALID;
1.7       timbl     635:            if (c!='>') {
                    636:                if (TRACE && !WHITE(c))
                    637:                    fprintf(stderr,"SGML:  `</%s%c' found!\n",
                    638:                        string->data, c);
                    639:                context->state = S_junk_tag;
                    640:            } else {
                    641:                context->state = S_text;
                    642:            }
1.1       timbl     643:        }
                    644:        break;
                    645: 
                    646:                
                    647:     case S_junk_tag:
                    648:        if (c=='>') {
                    649:            context->state = S_text;
                    650:        }
                    651:        
                    652:     } /* switch on context->state */
                    653: 
                    654: }  /* SGML_character */
1.2       timbl     655: 
                    656: 
                    657: PUBLIC void SGML_string ARGS2(HTStream *, context, CONST char*, str)
                    658: {
                    659:     CONST char *p;
                    660:     for(p=str; *p; p++)
                    661:         SGML_character(context, *p);
                    662: }
                    663: 
                    664: 
                    665: PUBLIC void SGML_write ARGS3(HTStream *, context, CONST char*, str, int, l)
                    666: {
                    667:     CONST char *p;
                    668:     CONST char *e = str+l;
                    669:     for(p=str; p<e; p++)
                    670:         SGML_character(context, *p);
                    671: }
                    672: 
                    673: /*_______________________________________________________________________
                    674: */
                    675: 
                    676: /*     Structured Object Class
                    677: **     -----------------------
                    678: */
                    679: PUBLIC CONST HTStreamClass SGMLParser = 
                    680: {              
                    681:        "SGMLParser",
                    682:        SGML_free,
1.8       timbl     683:        SGML_abort,
1.9       timbl     684:        SGML_character, 
                    685:        SGML_string,
                    686:        SGML_write,
1.2       timbl     687: }; 
                    688: 
                    689: /*     Create SGML Engine
                    690: **     ------------------
                    691: **
                    692: ** On entry,
                    693: **     dtd             represents the DTD, along with
                    694: **     actions         is the sink for the data as a set of routines.
                    695: **
                    696: */
                    697: 
                    698: PUBLIC HTStream* SGML_new  ARGS2(
                    699:        CONST SGML_dtd *,       dtd,
                    700:        HTStructured *,         target)
                    701: {
                    702:     int i;
                    703:     HTStream* context = (HTStream *) malloc(sizeof(*context));
                    704:     if (!context) outofmem(__FILE__, "SGML_begin");
                    705: 
                    706:     context->isa = &SGMLParser;
                    707:     context->string = HTChunkCreate(128);      /* Grow by this much */
                    708:     context->dtd = dtd;
                    709:     context->target = target;
                    710:     context->actions = (HTStructuredClass*)(((HTStream*)target)->isa);
                    711:                                        /* Ugh: no OO */
                    712:     context->state = S_text;
                    713:     context->element_stack = 0;                        /* empty */
                    714: #ifdef CALLERDATA                
                    715:     context->callerData = (void*) callerData;
                    716: #endif    
                    717:     for(i=0; i<MAX_ATTRIBUTES; i++) context->value[i] = 0;
                    718: 
                    719:     return context;
                    720: }
1.14    ! frystyk   721: 
        !           722: 
        !           723: 
        !           724: 
        !           725: 
        !           726: 
        !           727: 
        !           728: 
        !           729: 
        !           730: 
        !           731: 
1.2       timbl     732: 

Webmaster