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

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

Webmaster