📄 sgml.c
字号:
/* Handle sgmlatt** --------------*/PRIVATE void handle_sgmlatt ARGS1( HTStream *, context){ CONST char *s = context->string->data; CTRACE((tfp, "SGML Attribute Declaration:\n<%s>\n", s)); return;}/* * Convenience macros - tags (elements) are identified sometimes * by an int or enum value ('TAGNUM'), sometimes * by a pointer to HTTag ('TAGP'). - kw */#define TAGNUM_OF_TAGP(t) (t - context->dtd->tags)#define TAGP_OF_TAGNUM(e) (context->dtd->tags + e)/* * The following implement special knowledge about OBJECT. * As long as HTML_OBJECT is the only tag for which an alternative * variant exist, they can be simple macros. - kw *//* does 'TAGNUM' e have an alternative (variant) parsing mode? */#define HAS_ALT_TAGNUM(e) (e == HTML_OBJECT)/* return 'TAGNUM' of the alternative mode for 'TAGNUM' e, if any. */#define ALT_TAGNUM(e) ((e == HTML_OBJECT) ? HTML_ALT_OBJECT : e)/* return 'TAGNUM' of the normal mode for 'TAGNUM' e which may be alt. */#define NORMAL_TAGNUM(e) ((e >= HTML_ELEMENTS) ? HTML_OBJECT : e)/* More convenience stuff. - kw */#define ALT_TAGP_OF_TAGNUM(e) TAGP_OF_TAGNUM(ALT_TAGNUM(e))#define NORMAL_TAGP_OF_TAGNUM(e) TAGP_OF_TAGNUM(NORMAL_TAGNUM(e))#define ALT_TAGP(t) ALT_TAGP_OF_TAGNUM(TAGNUM_OF_TAGP(t))#define NORMAL_TAGP(t) NORMAL_TAGP_OF_TAGNUM(TAGNUM_OF_TAGP(t))#ifdef EXTENDED_HTMLDTDPRIVATE BOOL element_valid_within ARGS3( HTTag *, new_tag, HTTag *, stacked_tag, BOOL, direct){ TagClass usecontains, usecontained; if (!stacked_tag || !new_tag) return YES; usecontains = (direct ? stacked_tag->contains : stacked_tag->icontains); usecontained = (direct ? new_tag->contained : new_tag->icontained); if (new_tag == stacked_tag) return (BOOL) ((Tgc_same & usecontains) && (Tgc_same & usecontained)); else return (BOOL) ((new_tag->tagclass & usecontains) && (stacked_tag->tagclass & usecontained));}typedef enum { close_NO = 0, close_error = 1, close_valid = 2} canclose_t;PRIVATE canclose_t can_close ARGS2( HTTag *, new_tag, HTTag *, stacked_tag){ if (!stacked_tag) return close_NO; if (stacked_tag->flags & Tgf_endO) return close_valid; else if (new_tag == stacked_tag) return ((Tgc_same & new_tag->canclose) ? close_error : close_NO); else return ((stacked_tag->tagclass & new_tag->canclose) ? close_error : close_NO);}PRIVATE void do_close_stacked ARGS1( HTStream *, context){ HTElement * stacked = context->element_stack; HTMLElement e; if (!stacked) return; /* stack was empty */ if (context->inSELECT && !strcasecomp(stacked->tag->name, "SELECT")) { context->inSELECT = FALSE; } e = NORMAL_TAGNUM(TAGNUM_OF_TAGP(stacked->tag));#ifdef USE_PRETTYSRC if (!psrc_view) /* Don't actually pass call on if viewing psrc - kw */#endif (*context->actions->end_element)( context->target, e, (char **)&context->include); context->element_stack = stacked->next; pool_free(stacked); context->no_lynx_specialcodes = context->element_stack ? (context->element_stack->tag->flags & Tgf_nolyspcl) : NO;}PRIVATE int is_on_stack ARGS2( HTStream *, context, HTTag *, old_tag){ HTElement * stacked = context->element_stack; int i = 1; for (; stacked; stacked = stacked->next, i++) { if (stacked->tag == old_tag || stacked->tag == ALT_TAGP(old_tag)) return i; } return 0;}#endif /* EXTENDED_HTMLDTD *//* End element** -----------*/PRIVATE void end_element ARGS2( HTStream *, context, HTTag *, old_tag){#ifdef EXTENDED_HTMLDTD BOOL extra_action_taken = NO; canclose_t canclose_check = close_valid; int stackpos = is_on_stack(context, old_tag); if (!Old_DTD) { while (canclose_check != close_NO && context->element_stack && (stackpos > 1 || (!extra_action_taken && stackpos == 0))) { if (stackpos == 0 && (old_tag->flags & Tgf_startO) && element_valid_within(old_tag, context->element_stack->tag, YES)) { CTRACE((tfp, "SGML: </%s> ignored\n", old_tag->name)); return; } canclose_check = can_close(old_tag, context->element_stack->tag); if (canclose_check != close_NO) { CTRACE((tfp, "SGML: End </%s> \t<- %s end </%s>\n", context->element_stack->tag->name, canclose_check == close_valid ? "supplied," : "***forced by", old_tag->name)); do_close_stacked(context); extra_action_taken = YES; stackpos = is_on_stack(context, old_tag); } } if (stackpos == 0 && old_tag->contents != SGML_EMPTY) { CTRACE((tfp, "SGML: Still open %s, ***no open %s for </%s>\n", context->element_stack ? context->element_stack->tag->name : "none", old_tag->name, old_tag->name)); return; } if (stackpos > 1) { CTRACE((tfp, "SGML: Nesting <%s>...<%s> \t<- ***invalid end </%s>\n", old_tag->name, context->element_stack->tag->name, old_tag->name)); return; } } /* Now let the non-extended code deal with the rest. - kw */#endif /* EXTENDED_HTMLDTD */ /* ** If we are in a SELECT block, ignore anything ** but a SELECT end tag. - FM */ if (context->inSELECT) { if (!strcasecomp(old_tag->name, "SELECT")) { /* ** Turn off the inSELECT flag and fall through. - FM */ context->inSELECT = FALSE; } else { /* ** Ignore the end tag. - FM */ CTRACE((tfp, "SGML: ***Ignoring end tag </%s> in SELECT block.\n", old_tag->name)); return; } } /* ** Handle the end tag. - FM */ CTRACE((tfp, "SGML: End </%s>\n", old_tag->name)); if (old_tag->contents == SGML_EMPTY) { CTRACE((tfp, "SGML: ***Illegal end tag </%s> found.\n", old_tag->name)); return; }#ifdef WIND_DOWN_STACK while (context->element_stack) /* Loop is error path only */#else if (context->element_stack) /* Substitute and remove one stack element */#endif /* WIND_DOWN_STACK */ { int status = HT_OK; HTMLElement e; HTElement * N = context->element_stack; HTTag * t = (N->tag != old_tag) ? NORMAL_TAGP(N->tag) : N->tag; if (old_tag != t) { /* Mismatch: syntax error */ if (context->element_stack->next) { /* This is not the last level */ CTRACE((tfp, "SGML: Found </%s> when expecting </%s>. </%s> ***assumed.\n", old_tag->name, t->name, t->name)); } else { /* last level */ CTRACE((tfp, "SGML: Found </%s> when expecting </%s>. </%s> ***Ignored.\n", old_tag->name, t->name, old_tag->name)); return; /* Ignore */ } } e = NORMAL_TAGNUM(TAGNUM_OF_TAGP(t)); CTRACE2(TRACE_SGML, (tfp, "tagnum(%p) = %d\n", t, e));#ifdef USE_PRETTYSRC if (!psrc_view) /* Don't actually pass call on if viewing psrc - kw */#endif status = (*context->actions->end_element)(context->target, e, (char **)&context->include); if (status == HT_PARSER_REOPEN_ELT) { CTRACE((tfp, "SGML: Restart <%s>\n", t->name)); (*context->actions->start_element)( context->target, e, NULL, NULL, context->current_tag_charset, (char **)&context->include); } else if (status == HT_PARSER_OTHER_CONTENT) { CTRACE((tfp, "SGML: Continue with other content model for <%s>\n", t->name)); context->element_stack->tag = ALT_TAGP_OF_TAGNUM(e); } else { context->element_stack = N->next; /* Remove from stack */ pool_free(N); } context->no_lynx_specialcodes = context->element_stack ? (context->element_stack->tag->flags & Tgf_nolyspcl) : NO;#ifdef WIND_DOWN_STACK if (old_tag == t) return; /* Correct sequence */#else return;#endif /* WIND_DOWN_STACK */ /* Syntax error path only */ } CTRACE((tfp, "SGML: Extra end tag </%s> found and ignored.\n", old_tag->name));}/* Start a element*/PRIVATE void start_element ARGS1( HTStream *, context){ int status; HTTag * new_tag = context->current_tag; HTMLElement e = TAGNUM_OF_TAGP(new_tag); BOOL ok = FALSE;#ifdef EXTENDED_HTMLDTD BOOL valid = YES; BOOL direct_container = YES; BOOL extra_action_taken = NO; canclose_t canclose_check = close_valid; if (!Old_DTD) { while (context->element_stack && (canclose_check == close_valid || (canclose_check == close_error && new_tag == context->element_stack->tag)) && !(valid = element_valid_within(new_tag, context->element_stack->tag, direct_container))) { canclose_check = can_close(new_tag, context->element_stack->tag); if (canclose_check != close_NO) { CTRACE((tfp, "SGML: End </%s> \t<- %s start <%s>\n", context->element_stack->tag->name, canclose_check == close_valid ? "supplied," : "***forced by", new_tag->name)); do_close_stacked(context); extra_action_taken = YES; if (canclose_check == close_error) direct_container = NO; } else { CTRACE((tfp, "SGML: Still open %s \t<- ***invalid start <%s>\n", context->element_stack->tag->name, new_tag->name)); } } if (context->element_stack && !valid && (context->element_stack->tag->flags & Tgf_strict) && !(valid = element_valid_within(new_tag, context->element_stack->tag, direct_container))) { CTRACE((tfp, "SGML: Still open %s \t<- ***ignoring start <%s>\n", context->element_stack->tag->name, new_tag->name)); return; } if (context->element_stack && !extra_action_taken && canclose_check == close_NO && !valid && (new_tag->flags & Tgf_mafse)) { BOOL has_attributes = NO; int i = 0; for (; i< new_tag->number_of_attributes && !has_attributes; i++) has_attributes = context->present[i]; if (!has_attributes) { CTRACE((tfp, "SGML: Still open %s, ***converting invalid <%s> to </%s>\n", context->element_stack->tag->name, new_tag->name, new_tag->name)); end_element(context, new_tag); return; } } if (context->element_stack && canclose_check == close_error && !(valid = element_valid_within( new_tag, context->element_stack->tag, direct_container))) { CTRACE((tfp, "SGML: Still open %s \t<- ***invalid start <%s>\n", context->element_stack->tag->name, new_tag->name)); } } /* Fall through to the non-extended code - kw */#endif /* EXTENDED_HTMLDTD */ /* ** If we are not in a SELECT block, check if this is ** a SELECT start tag. Otherwise (i.e., we are in a ** SELECT block) accept only OPTION as valid, terminate ** the SELECT block if it is any other form-related ** element, and otherwise ignore it. - FM */ if (!context->inSELECT) { /* ** We are not in a SELECT block, so check if this starts one. - FM ** (frequent case!) */ /* my_casecomp() - optimized by the first character */ if (!my_casecomp(new_tag->name, "SELECT")) { /* ** Set the inSELECT flag and fall through. - FM */ context->inSELECT = TRUE; } } else { /* ** We are in a SELECT block. - FM */ if (strcasecomp(new_tag->name, "OPTION")) { /* ** Ugh, it is not an OPTION. - FM */ switch (e) { case HTML_INPUT: case HTML_TEXTAREA: case HTML_SELECT: case HTML_BUTTON: case HTML_FIELDSET: case HTML_LABEL: case HTML_LEGEND: case HTML_FORM: ok = TRUE; break; default: break; } if (ok) { /* ** It is another form-related start tag, so terminate ** the current SELECT block and fall through. - FM */ CTRACE((tfp, "SGML: ***Faking SELECT end tag before <%s> start tag.\n", new_tag->name)); end_element(context, SGMLFindTag(context->dtd, "SELECT")); } else { /* ** Ignore the start tag. - FM */ CTRACE((tfp, "SGML: ***Ignoring start tag <%s> in SELECT block.\n", new_tag->name)); return; } } } /* ** Handle the start tag. - FM */ CTRACE((tfp, "SGML: Start <%s>\n", new_tag->name)); status = (*context->actions->start_element)( context->target, TAGNUM_OF_TAGP(new_tag), context->present, (CONST char**) context->value, /* coerce type for think c */ context->current_tag_charset, (char **)&context->include); if (status == HT_PARSER_OTHER_CONTENT) new_tag = ALT_TAGP(new_tag); /* this is only returned for OBJECT */ if (new_tag->contents != SGML_EMPTY) { /* i.e., tag not empty */ HTElement * N = pool_alloc(); if (N == NULL) outofmem(__FILE__, "start_element"); N->next = context->element_stack; N->tag = new_tag; context->element_stack = N; context->no_lynx_specialcodes = (new_tag->flags & Tgf_nolyspcl); } else if (e == HTML_META ) { /* ** Check for result of META tag. - KW & FM */ change_chartrans_handling(context); }}/* Find Tag in DTD tag list** ------------------------**** On entry,** dtd points to dtd structure including valid tag list** string points to name of tag in question**** On exit,** returns:** NULL tag not found** else address of tag structure in dtd*/PUBLIC HTTag * SGMLFindTag ARGS2( CONST SGML_dtd*, dtd, CONST char *, s){ int high, low, i, diff; static HTTag* last[64] = {NULL}; /*optimize using the previous results*/ HTTag** res = last + (UCH(*s) % 64); /*pointer arithmetic*/ if (*res && !strcasecomp((*res)->name, s)) return *res; for (low = 0, high=dtd->number_of_tags; high > low; diff < 0 ? (low = i+1) : (high = i)) { /* Binary search */ i = (low + (high-low)/2); /* my_casecomp() - optimized by the first character, NOT_ASCII ok */ diff = my_casecomp(dtd->tags[i].name, s); /* Case insensitive */ if (diff == 0) { /* success: found it */ *res = &dtd->tags[i]; return *res; } } if (IsNmStart(*s)) { /* ** Unrecognized, but may be valid. - KW
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -