home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lynx2.8.1dev.10.tar.gz / lynx2.8.1dev.10.tar / lynx2-8 / src / HTML.c < prev    next >
C/C++ Source or Header  |  1998-05-10  |  216KB  |  7,454 lines

  1. /*        Structured stream to Rich hypertext converter
  2. **        ============================================
  3. **
  4. **    This generates a hypertext object.  It converts from the
  5. **    structured stream interface of HTML events into the style-
  6. **    oriented interface of the HText.h interface.  This module is
  7. **    only used in clients and should not be linked into servers.
  8. **
  9. **    Override this module if making a new GUI browser.
  10. **
  11. **   Being Overidden
  12. **
  13. */
  14. #define DICKEY_TEST
  15.  
  16. #include <HTUtils.h>
  17. #include <tcp.h>
  18.  
  19. #define Lynx_HTML_Handler
  20. #include <HTChunk.h>
  21. #include <HText.h>
  22. #include <HTStyle.h>
  23. #include <HTML.h>
  24.  
  25. #include <HTCJK.h>
  26. #include <HTAtom.h>
  27. #include <HTAnchor.h>
  28. #include <HTMLGen.h>
  29. #include <HTParse.h>
  30. #include <HTList.h>
  31. #include <UCMap.h>
  32. #include <UCDefs.h>
  33. #include <UCAux.h>
  34.  
  35. #include <LYGlobalDefs.h>
  36. #include <LYCharUtils.h>
  37. #include <LYCharSets.h>
  38.  
  39. #include <HTAlert.h>
  40. #include <HTFont.h>
  41. #include <HTForms.h>
  42. #include <HTNestedList.h>
  43. #include <GridText.h>
  44. #include <LYSignal.h>
  45. #include <LYStrings.h>
  46. #include <LYUtils.h>
  47. #include <LYMap.h>
  48. #include <LYList.h>
  49. #include <LYBookmark.h>
  50.  
  51. #ifdef VMS
  52. #include <LYCurses.h>
  53. #include <HTVMSUtils.h>
  54. #endif /* VMS */
  55.  
  56. #ifdef USE_COLOR_STYLE
  57. #include <AttrList.h>
  58. #include <LYHash.h>
  59. #include <LYStyle.h>
  60. #undef SELECTED_STYLES
  61. #define pHText_changeStyle(X,Y,Z) {}
  62. char Style_className[16384];
  63. #endif
  64.  
  65. #include <LYexit.h>
  66. #include <LYLeaks.h>
  67.  
  68. #define FREE(x) if (x) {free(x); x = NULL;}
  69.  
  70. #define STACKLEVEL(me) ((me->stack + MAX_NESTING - 1) - me->sp)
  71.  
  72. extern BOOL HTPassEightBitRaw;
  73. extern HTCJKlang HTCJK;
  74.  
  75. extern BOOLEAN HT_Is_Gopher_URL;
  76.  
  77. /* from Curses.h */
  78. extern int LYcols;
  79.  
  80. struct _HTStream {
  81.     CONST HTStreamClass *    isa;
  82.     /* .... */
  83. };
  84.  
  85. PRIVATE HTStyleSheet * styleSheet;    /* Application-wide */
  86.  
  87. /*    Module-wide style cache
  88. */
  89. PUBLIC    HTStyle *styles[HTML_ELEMENTS+31]; /* adding 24 nested list styles  */
  90.                        /* and 3 header alignment styles */
  91.                        /* and 3 div alignment styles    */
  92. PRIVATE HTStyle *default_style;
  93.  
  94. PUBLIC char *LYToolbarName = "LynxPseudoToolbar";
  95.  
  96. /* used to turn off a style if the HTML author forgot to
  97. PRIVATE int i_prior_style = -1;
  98.  */
  99.  
  100. /*
  101.  *    Private function....
  102.  */
  103. PRIVATE void HTML_end_element PARAMS((HTStructured *me,
  104.                       int element_number,
  105.                       char **include));
  106.  
  107. /*        Forward declarations of routines
  108. */
  109. PRIVATE void get_styles NOPARAMS;
  110. PRIVATE void change_paragraph_style PARAMS((HTStructured * me,
  111.                         HTStyle * style));
  112.  
  113. /*
  114.  * If we have verbose_img set, display labels for images.
  115.  */
  116. #define VERBOSE_IMG(value,string) \
  117.       ((verbose_img) ? (newtitle = MakeNewTitle(value)): string)
  118.  
  119. PRIVATE char * MakeNewTitle PARAMS((CONST char ** value));
  120.  
  121. /*    Set an internal flag that the next call to a stack-affecting method
  122. **    is only internal and the stack manipulation should be skipped. - kw
  123. */
  124. #define SET_SKIP_STACK(el_num) if (HTML_dtd.tags[el_num].contents != SGML_EMPTY) \
  125.                         { me->skip_stack++; }
  126.  
  127. extern int hash_code PARAMS((char* i));
  128.  
  129. PUBLIC void strtolower ARGS1(char*, i)
  130. {
  131.     if (!i) return;
  132.     while (*i) { *i=tolower(*i); i++; }
  133. }
  134.  
  135. /*        Flattening the style structure
  136. **        ------------------------------
  137. **
  138. On the NeXT, and on any read-only browser, it is simpler for the text to have
  139. a sequence of styles, rather than a nested tree of styles. In this
  140. case we have to flatten the structure as it arrives from SGML tags into
  141. a sequence of styles.
  142. */
  143.  
  144. /*
  145. **  If style really needs to be set, call this.
  146. */
  147. PUBLIC void actually_set_style ARGS1(HTStructured *, me)
  148. {
  149.     if (!me->text) {            /* First time through */
  150.     LYGetChartransInfo(me);
  151.     UCSetTransParams(&me->T,
  152.              me->UCLYhndl, me->UCI,
  153.              HTAnchor_getUCLYhndl(me->node_anchor,
  154.                           UCT_STAGE_HTEXT),
  155.              HTAnchor_getUCInfoStage(me->node_anchor,
  156.                          UCT_STAGE_HTEXT));
  157.     me->text = HText_new2(me->node_anchor, me->target);
  158.     HText_beginAppend(me->text);
  159.     HText_setStyle(me->text, me->new_style);
  160.     me->in_word = NO;
  161.     LYCheckForContentBase(me);
  162.     } else {
  163.     HText_setStyle(me->text, me->new_style);
  164.     }
  165.  
  166.     me->old_style = me->new_style;
  167.     me->style_change = NO;
  168. }
  169.  
  170. /*
  171. **  If you THINK you need to change style, call this.
  172. */
  173. PRIVATE void change_paragraph_style ARGS2(HTStructured *, me, HTStyle *,style)
  174. {
  175.     if (me->new_style != style) {
  176.     me->style_change = YES;
  177.     me->new_style = style;
  178.     }
  179.     me->in_word = NO;
  180. }
  181.  
  182. /*_________________________________________________________________________
  183. **
  184. **            A C T I O N    R O U T I N E S
  185. */
  186.  
  187. /*    Character handling
  188. **    ------------------
  189. */
  190. PUBLIC void HTML_put_character ARGS2(HTStructured *, me, char, c)
  191. {
  192.     /*
  193.      *    Ignore all non-MAP content when just
  194.      *    scanning a document for MAPs. - FM
  195.      */
  196.     if (LYMapsOnly)
  197.     return;
  198.  
  199.     /*
  200.      *    Do EOL conversion if needed. - FM
  201.      *
  202.      *    Convert EOL styles:
  203.      *     macintosh:  cr    --> lf
  204.      *     ascii:      cr-lf --> lf
  205.      *     unix:         lf    --> lf
  206.      */
  207.     if ((me->lastraw == '\r') && c == '\n') {
  208.     me->lastraw = -1;
  209.     return;
  210.     }
  211.     me->lastraw = c;
  212.     if (c == '\r')
  213.     c = '\n';
  214.  
  215.     /*
  216.      *    Handle SGML_LITTERAL tags that have HTChunk elements. - FM
  217.      */
  218.     switch (me->sp[0].tag_number) {
  219.  
  220.     case HTML_COMMENT:
  221.     return; /* Do Nothing */
  222.  
  223.     case HTML_TITLE:
  224.     if (c == LY_SOFT_HYPHEN)
  225.         return;
  226.     if (c != '\n' && c != '\t' && c != '\r')
  227.         HTChunkPutc(&me->title, c);
  228.     else
  229.         HTChunkPutc(&me->title, ' ');
  230.     return;
  231.  
  232.     case HTML_STYLE:
  233.     HTChunkPutc(&me->style_block, c);
  234.     return;
  235.  
  236.     case HTML_SCRIPT:
  237.     HTChunkPutc(&me->script, c);
  238.     return;
  239.  
  240.     case HTML_OBJECT:
  241.     HTChunkPutc(&me->object, c);
  242.     return;
  243.  
  244.     case HTML_TEXTAREA:
  245.     HTChunkPutc(&me->textarea, c);
  246.     return;
  247.  
  248.     case HTML_SELECT:
  249.     case HTML_OPTION:
  250.     HTChunkPutc(&me->option, c);
  251.     return;
  252.  
  253.     case HTML_MATH:
  254.     HTChunkPutc(&me->math, c);
  255.     return;
  256.  
  257.     default:
  258.     if (me->inSELECT) {
  259.         /*
  260.          *    If we are within a SELECT not caught by the cases
  261.          *    above - HTML_SELECT or HTML_OPTION may not be the
  262.          *    last element pushed on the style stack if there were
  263.          *    invalid markup tags within a SELECT element.  For error
  264.          *    recovery, treat text as part of the OPTION text, it is
  265.          *    probably meant to show up as user-visible text.
  266.          *    Having A as an open element while in SELECT is really sick,
  267.          *    don't make anchor text part of the option text in that case
  268.          *    since the option text will probably just be discarded. - kw
  269.          */
  270.         if (me->sp[0].tag_number == HTML_A)
  271.         break;
  272.         HTChunkPutc(&me->option, c);
  273.         return;
  274.     }
  275.     break;
  276.     } /* end first switch */
  277.  
  278.     /*
  279.      *    Handle all other tag content. - FM
  280.      */
  281.     switch (me->sp[0].tag_number) {
  282.  
  283.     case HTML_PRE:                /* Formatted text */
  284.     /*
  285.      *  We guarantee that the style is up-to-date in begin_litteral
  286.      *  But we still want to strip \r's
  287.      */
  288.     if (c != '\r' &&
  289.         !(c == '\n' && me->inLABEL && !me->inP) &&
  290.         !(c == '\n' && !me->inPRE)) {
  291.         me->inP = TRUE;
  292.         me->inLABEL = FALSE;
  293.         HText_appendCharacter(me->text, c);
  294.     }
  295.     me->inPRE = TRUE;
  296.     break;
  297.  
  298.     case HTML_LISTING:                /* Literal text */
  299.     case HTML_XMP:
  300.     case HTML_PLAINTEXT:
  301.     /*
  302.      *  We guarantee that the style is up-to-date in begin_litteral
  303.      *  But we still want to strip \r's
  304.      */
  305.     if (c != '\r')    {
  306.         me->inP = TRUE;
  307.         me->inLABEL = FALSE;
  308.         HText_appendCharacter(me->text, c);
  309.     }
  310.     break;
  311.  
  312.     default:
  313.     /*
  314.      *  Free format text.
  315.      */
  316.     if (!strcmp(me->sp->style->name,"Preformatted")) {
  317.         if (c != '\r' &&
  318.         !(c == '\n' && me->inLABEL && !me->inP) &&
  319.         !(c == '\n' && !me->inPRE)) {
  320.         me->inP = TRUE;
  321.         me->inLABEL = FALSE;
  322.         HText_appendCharacter(me->text, c);
  323.         }
  324.         me->inPRE = TRUE;
  325.  
  326.     } else if (!strcmp(me->sp->style->name,"Listing") ||
  327.            !strcmp(me->sp->style->name,"Example")) {
  328.         if (c != '\r') {
  329.         me->inP = TRUE;
  330.         me->inLABEL = FALSE;
  331.         HText_appendCharacter(me->text, c);
  332.         }
  333.  
  334.     } else {
  335.         if (me->style_change) {
  336.         if ((c == '\n') || (c == ' '))
  337.             return;    /* Ignore it */
  338.         UPDATE_STYLE;
  339.         }
  340.         if (c == '\n') {
  341.         if (me->in_word) {
  342.             if (HText_getLastChar(me->text) != ' ') {
  343.             me->inP = TRUE;
  344.             me->inLABEL = FALSE;
  345.             HText_appendCharacter(me->text, ' ');
  346.             }
  347.             me->in_word = NO;
  348.         }
  349.  
  350.         } else if (c == ' ' || c == '\t') {
  351.         if (HText_getLastChar(me->text) != ' ') {
  352.             me->inP = TRUE;
  353.             me->inLABEL = FALSE;
  354.             HText_appendCharacter(me->text, ' ');
  355.         }
  356.  
  357.         } else if (c == '\r') {
  358.            /* ignore */
  359.  
  360.         } else {
  361.         me->inP = TRUE;
  362.         me->inLABEL = FALSE;
  363.         HText_appendCharacter(me->text, c);
  364.         me->in_word = YES;
  365.         }
  366.     }
  367.     } /* end second switch */
  368.  
  369.     if (c == '\n' || c == '\t') {
  370.     HText_setLastChar(me->text, ' '); /* set it to a generic seperater */
  371.  
  372.     /*
  373.      *  \r's are ignored.  In order to keep collapsing spaces
  374.      *  correctly we must default back to the previous
  375.      *  seperater if there was one
  376.      */
  377.     } else if (c == '\r' && HText_getLastChar(me->text) == ' ') {
  378.     HText_setLastChar(me->text, ' '); /* set it to a generic seperater */
  379.     } else {
  380.     HText_setLastChar(me->text, c);
  381.     }
  382. }
  383.  
  384. /*    String handling
  385. **    ---------------
  386. **
  387. **    This is written separately from put_character because the loop can
  388. **    in some cases be promoted to a higher function call level for speed.
  389. */
  390. PUBLIC void HTML_put_string ARGS2(HTStructured *, me, CONST char *, s)
  391. {
  392.    if (LYMapsOnly || s == NULL)
  393.       return;
  394.  
  395.     switch (me->sp[0].tag_number) {
  396.  
  397.     case HTML_COMMENT:
  398.     break;                    /* Do Nothing */
  399.  
  400.     case HTML_TITLE:
  401.     HTChunkPuts(&me->title, s);
  402.     break;
  403.  
  404.     case HTML_STYLE:
  405.     HTChunkPuts(&me->style_block, s);
  406.     break;
  407.  
  408.     case HTML_SCRIPT:
  409.     HTChunkPuts(&me->script, s);
  410.     break;
  411.  
  412.     case HTML_PRE:                /* Formatted text */
  413.     case HTML_LISTING:                /* Literal text */
  414.     case HTML_XMP:
  415.     case HTML_PLAINTEXT:
  416.     /*
  417.      *  We guarantee that the style is up-to-date in begin_litteral
  418.      */
  419.     HText_appendText(me->text, s);
  420.     break;
  421.  
  422.     case HTML_OBJECT:
  423.     HTChunkPuts(&me->object, s);
  424.     break;
  425.  
  426.     case HTML_TEXTAREA:
  427.     HTChunkPuts(&me->textarea, s);
  428.     break;
  429.  
  430.     case HTML_SELECT:
  431.     case HTML_OPTION:
  432.     HTChunkPuts(&me->option, s);
  433.     break;
  434.  
  435.     case HTML_MATH:
  436.     HTChunkPuts(&me->math, s);
  437.     break;
  438.  
  439.     default:                    /* Free format text? */
  440.     if (!me->sp->style->freeFormat) {
  441.         /*
  442.          *    If we are within a preformatted text style not caught
  443.          *    by the cases above (HTML_PRE or similar may not be the
  444.          *    last element pushed on the style stack). - kw
  445.          */
  446.         HText_appendText(me->text, s);
  447.         break;
  448.     } else {
  449.         CONST char *p = s;
  450.         char c;
  451.         if (me->style_change) {
  452.         for (; *p && ((*p == '\n') || (*p == '\r') ||
  453.                   (*p == ' ') || (*p == '\t')); p++)
  454.             ;    /* Ignore leaders */
  455.         if (!*p)
  456.             return;
  457.         UPDATE_STYLE;
  458.         }
  459.         for (; *p; p++) {
  460.         if (*p == 13 && p[1] != 10) {
  461.             /*
  462.              *    Treat any '\r' which is not followed by '\n'
  463.              *    as '\n', to account for macintosh lineend in
  464.              *    ALT attributes etc. - kw
  465.              */
  466.             c = '\n';
  467.         } else {
  468.             c = *p;
  469.         }
  470.         if (me->style_change) {
  471.             if ((c == '\n') || (c == ' ') || (c == '\t'))
  472.             continue;  /* Ignore it */
  473.             UPDATE_STYLE;
  474.         }
  475.         if (c == '\n') {
  476.             if (me->in_word) {
  477.             if (HText_getLastChar(me->text) != ' ')
  478.                 HText_appendCharacter(me->text, ' ');
  479.             me->in_word = NO;
  480.             }
  481.  
  482.         } else if (c == ' ' || c == '\t') {
  483.            if (HText_getLastChar(me->text) != ' ')
  484.             HText_appendCharacter(me->text, ' ');
  485.  
  486.         } else if (c == '\r') {
  487.             /* ignore */
  488.         } else {
  489.             HText_appendCharacter(me->text, c);
  490.             me->in_word = YES;
  491.         }
  492.  
  493.         /* set the Last Character */
  494.         if (c == '\n' || c == '\t') {
  495.             /* set it to a generic seperater */
  496.             HText_setLastChar(me->text, ' ');
  497.         } else if (c == '\r' &&
  498.                HText_getLastChar(me->text) == ' ') {
  499.             /*
  500.              *    \r's are ignored.  In order to keep collapsing
  501.              *    spaces correctly, we must default back to the
  502.              *    previous seperator, if there was one.  So we
  503.              *    set LastChar to a generic seperater.
  504.              */
  505.             HText_setLastChar(me->text, ' ');
  506.         } else {
  507.             HText_setLastChar(me->text, c);
  508.         }
  509.  
  510.         } /* for */
  511.     }
  512.     } /* end switch */
  513. }
  514.  
  515. /*    Buffer write
  516. **    ------------
  517. */
  518. PUBLIC void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
  519. {
  520.     CONST char* p;
  521.     CONST char* e = s+l;
  522.  
  523.     if (LYMapsOnly)
  524.     return;
  525.  
  526.     for (p = s; s < e; p++)
  527.     HTML_put_character(me, *p);
  528. }
  529.  
  530. /*
  531.  *  "Internal links" are hyperlinks whose source and destination are
  532.  *  within the same document, and for which the destination is given
  533.  *  as a URL Reference with an empty URL, but possibly with a non-empty
  534.  *  #fragment.    (This terminology re URL-Reference vs. URL follows the
  535.  *  Fielding URL syntax and semantics drafts).
  536.  *  Differences:
  537.  *  (1) The document's base (in whatever way it is given) is not used for
  538.  *    resolving internal link references.
  539.  *  (2) Activating an internal link should not result in a new retrieval
  540.  *    of a copy of the document.
  541.  *  (3) Internal links are the only way to refer with a hyperlink to a document
  542.  *    (or a location in it) which is only known as the result of a POST
  543.  *    request (doesn't have a URL from which the document can be retrieved
  544.  *    with GET), and can only be used from within that document.
  545.  *
  546.  * *If DONT_TRACK_INTERNAL_LINKS is not defined, we keep track of whether a
  547.  *  link destination was given as an internal link.  This information is
  548.  *  recorded in the type of the link between anchor objects, and is available
  549.  *  to the HText object and the mainloop from there.  URL References to
  550.  *  internal destinations are still resolved into an absolute form before
  551.  *  being passed on, but using the current stream's retrieval address instead
  552.  *  of the base URL.
  553.  *  Examples:  (replace [...] to have a valid absolute URL)
  554.  *  In document retrieved from [...]/mypath/mydoc.htm w/ base [...]/otherpath/
  555.  *  a. HREF="[...]/mypath/mydoc.htm"      -> [...]/mypath/mydoc.htm
  556.  *  b. HREF="[...]/mypath/mydoc.htm#frag" -> [...]/mypath/mydoc.htm#frag
  557.  *  c. HREF="mydoc.htm"           -> [...]/otherpath/mydoc.htm
  558.  *  d. HREF="mydoc.htm#frag"          -> [...]/otherpath/mydoc.htm#frag
  559.  *  e. HREF=""              -> [...]/mypath/mydoc.htm      (marked internal)
  560.  *  f. HREF="#frag"          -> [...]/mypath/mydoc.htm#frag (marked internal)
  561.  *
  562.  * *If DONT_TRACK_INTERNAL_LINKS is defined, URL-less URL-References are
  563.  *  resolved differently from URL-References with a non-empty URL (using the
  564.  *  current stream's retrieval address instead of the base), but we make no
  565.  *  further distinction.  Resolution is then as in the examples above, execept
  566.  *  that there is no "(marked internal)".
  567.  *
  568.  * *Note that this doesn't apply to form ACTIONs (always resolved using base,
  569.  *  never marked internal).  Also other references encountered or generated
  570.  *  are not marked internal, whether they have a URL or not, if in a given
  571.  *  context an internal link makes no sense (e.g. IMG SRC=).
  572.  */
  573.  
  574. #ifndef DONT_TRACK_INTERNAL_LINKS
  575. /* A flag is used to keep track of whether an "URL reference" encountered
  576.    had a real "URL" or not. In the latter case, it will be marked as
  577.    "internal".    The flag is set before we start messing around with the
  578.    string (resolution of relative URLs etc.). This variable only used
  579.    locally here, don't confuse with LYinternal_flag which is for
  580.    for overriding non-caching similar to LYoverride_no_cache. - kw */
  581. #define CHECK_FOR_INTERN(s) intern_flag = (s && (*s=='#' || *s=='\0')) ? TRUE : FALSE;
  582.  
  583. /* Last argument to pass to HTAnchor_findChildAndLink() calls,
  584.    just an abbreviation. - kw */
  585. #define INTERN_LT (HTLinkType *)(intern_flag ? LINK_INTERNAL : NULL)
  586.  
  587. #else  /* !DONT_TRACK_INTERNAL_LINKS */
  588.  
  589. #define CHECK_FOR_INTERN(s)  /* do nothing */ ;
  590. #define INTERN_LT (HTLinkType *)NULL
  591.  
  592. #endif /* DONT_TRACK_INTERNAL_LINKS */
  593.  
  594. #ifdef USE_COLOR_STYLE
  595. char class_string[TEMPSTRINGSIZE];
  596. char prevailing_class[TEMPSTRINGSIZE];
  597. #endif
  598.  
  599. #ifdef USE_COLOR_STYLE
  600.     char myHash[128];
  601.     int hcode;
  602. #endif
  603.  
  604. /*    Start Element
  605. **    -------------
  606. */
  607. PRIVATE void HTML_start_element ARGS6(
  608.     HTStructured *,     me,
  609.     int,            element_number,
  610.     CONST BOOL*,        present,
  611.     CONST char **,        value,
  612.     int,            tag_charset,
  613.     char **,        include)
  614. {
  615.     char *alt_string = NULL;
  616.     char *id_string = NULL;
  617.     char *newtitle = NULL;
  618.     char *href = NULL;
  619.     char *map_href = NULL;
  620.     char *title = NULL;
  621.     char *I_value = NULL;
  622.     char *I_name = NULL;
  623.     char *temp = NULL;
  624.     int dest_char_set  = -1;
  625.     HTParentAnchor *dest = NULL;         /* An anchor's destination */
  626.     BOOL dest_ismap = FALSE;             /* Is dest an image map script? */
  627.     BOOL UseBASE = TRUE;             /* Resoved vs. BASE if present? */
  628.     HTChildAnchor *ID_A = NULL;          /* HTML_foo_ID anchor */
  629.     int url_type = 0, i = 0;
  630.     char *cp = NULL;
  631.     int ElementNumber = element_number;
  632.     BOOL intern_flag = FALSE;
  633.  
  634.     if (LYMapsOnly) {
  635.     if (!(ElementNumber == HTML_MAP || ElementNumber == HTML_AREA ||
  636.           ElementNumber == HTML_BASE)) {
  637.         return;
  638.     }
  639.     } else if (!me->text) {
  640.     UPDATE_STYLE;
  641.     }
  642.  
  643.     if (tag_charset < 0)
  644.     me->tag_charset = me->UCLYhndl;
  645.     else
  646.     me->tag_charset = tag_charset;
  647.  
  648. /* this should be done differently */
  649. #if defined(USE_COLOR_STYLE)
  650.     strcat (Style_className, ";");
  651.     strcat (Style_className, HTML_dtd.tags[element_number].name);
  652.     strcpy (myHash, HTML_dtd.tags[element_number].name);
  653.     if (class_string[0])
  654.     {
  655.         strcat (Style_className, ".");
  656.         strcat (Style_className, class_string);
  657.         strcat (myHash, ".");
  658.         strcat (myHash, class_string);
  659. #ifdef PREVAIL
  660.         strcpy (prevailing_class, class_string);
  661. #endif
  662.     }
  663. #ifdef PREVAIL
  664.     else if (prevailing_class[0])
  665.     {
  666.         strcat (Style_className, ".");
  667.         strcat (Style_className, prevailing_class);
  668.         strcat (myHash, ".");
  669.         strcat (myHash, prevailing_class);
  670.     }
  671. #endif /* PREVAIL */
  672.     class_string[0]='\0';
  673.     strtolower(myHash);
  674.     hcode=hash_code(myHash);
  675.     strtolower(Style_className);
  676.  
  677.     if (TRACE)
  678.     {
  679.         fprintf(tfp, "CSSTRIM:%s -> %d", myHash, hcode);
  680.         if (hashStyles[hcode].code!=hcode)
  681.         {
  682.             char *rp=strrchr(myHash, '.');
  683.             fprintf(tfp, " (undefined) %s\n", myHash);
  684.             if (rp)
  685.             {
  686.                 int hcd;
  687.                 *rp='\0'; /* trim the class */
  688.                 hcd = hash_code(myHash);
  689.                 fprintf(tfp, "CSS:%s -> %d", myHash, hcd);
  690.                 if (hashStyles[hcd].code!=hcd)
  691.                     fprintf(tfp, " (undefined) %s\n", myHash);
  692.                 else
  693.                     fprintf(tfp, " ca=%d\n", hashStyles[hcd].color);
  694.             }
  695.         }
  696.         else
  697.             fprintf(tfp, " ca=%d\n", hashStyles[hcode].color);
  698.     }
  699.  
  700.     if (displayStyles[element_number + STARTAT].color > -2) /* actually set */
  701.     {
  702.     CTRACE(tfp, "CSSTRIM: start_element: top <%s>\n", HTML_dtd.tags[element_number].name);
  703.     HText_characterStyle(me->text, hcode, 1);
  704.     }
  705. #endif /* USE_COLOR_STYLE */
  706.  
  707.     /*
  708.      *    Handle the start tag. - FM
  709.      */
  710.     switch (ElementNumber) {
  711.  
  712.     case HTML_HTML:
  713.     break;
  714.  
  715.     case HTML_HEAD:
  716.     break;
  717.  
  718.     case HTML_BASE:
  719.     if (present && present[HTML_BASE_HREF] && !local_host_only &&
  720.         value[HTML_BASE_HREF] && *value[HTML_BASE_HREF]) {
  721.         char *base = NULL;
  722.         char *related = NULL;
  723.  
  724.         StrAllocCopy(base, value[HTML_BASE_HREF]);
  725.         if (!(url_type = LYLegitimizeHREF(me, (char**)&base,
  726.                           TRUE, TRUE))) {
  727.         CTRACE(tfp, "HTML: BASE '%s' is not an absolute URL.\n",
  728.                 (base ? base : ""));
  729.         if (me->inBadBASE == FALSE)
  730.             HTAlert(BASE_NOT_ABSOLUTE);
  731.         me->inBadBASE = TRUE;
  732.         }
  733.  
  734.         if (url_type == LYNXIMGMAP_URL_TYPE) {
  735.         /*
  736.          *  These have a are non-standard form, basically
  737.          *  strip the prefix or the code below would insert
  738.          *  a nonsense host into the pseudo URL.  These
  739.          *  should never occur where they would used for
  740.          *  resolution of relative URLs anyway.  We can
  741.          *  also strip the #map part. - kw
  742.          */
  743.         temp = HTParse(base + 11, "",
  744.                    PARSE_ACCESS+PARSE_HOST+PARSE_PATH
  745.                    +PARSE_PUNCTUATION);
  746.         if (temp) {
  747.             FREE(base);
  748.             base = temp;
  749.             temp = NULL;
  750.         }
  751.         }
  752.  
  753.         /*
  754.          *    Get parent's address for defaulted fields.
  755.          */
  756.         StrAllocCopy(related, me->node_anchor->address);
  757.  
  758.         /*
  759.          *    Create the access field.
  760.          */
  761.         if ((temp = HTParse(base, related,
  762.                 PARSE_ACCESS+PARSE_PUNCTUATION)) &&
  763.         *temp != '\0') {
  764.         StrAllocCopy(me->base_href, temp);
  765.         } else {
  766.         FREE(temp);
  767.         StrAllocCopy(me->base_href, (temp = HTParse(related, "",
  768.                      PARSE_ACCESS+PARSE_PUNCTUATION)));
  769.         }
  770.         FREE(temp);
  771.  
  772.         /*
  773.          *    Create the host[:port] field.
  774.          */
  775.         if ((temp = HTParse(base, "",
  776.                 PARSE_HOST+PARSE_PUNCTUATION)) &&
  777.         !strncmp(temp, "//", 2)) {
  778.         StrAllocCat(me->base_href, temp);
  779.         if (!strcmp(me->base_href, "file://")) {
  780.             StrAllocCat(me->base_href, "localhost");
  781.         }
  782.         } else {
  783.         if (!strcmp(me->base_href, "file:")) {
  784.             StrAllocCat(me->base_href, "//localhost");
  785.         } else if (strcmp(me->base_href, "news:")) {
  786.             FREE(temp);
  787.             StrAllocCat(me->base_href, (temp = HTParse(related, "",
  788.                         PARSE_HOST+PARSE_PUNCTUATION)));
  789.         }
  790.         }
  791.         FREE(temp);
  792.         FREE(related);
  793.  
  794.         /*
  795.          *    Create the path field.
  796.          */
  797.         if ((temp = HTParse(base, "",
  798.                 PARSE_PATH+PARSE_PUNCTUATION)) &&
  799.         *temp != '\0') {
  800.         StrAllocCat(me->base_href, temp);
  801.         } else if (!strcmp(me->base_href, "news:")) {
  802.         StrAllocCat(me->base_href, "*");
  803.         } else if (!strncmp(me->base_href, "news:", 5) ||
  804.                !strncmp(me->base_href, "nntp:", 5) ||
  805.                !strncmp(me->base_href, "snews:", 6)) {
  806.         StrAllocCat(me->base_href, "/*");
  807.         } else {
  808.         StrAllocCat(me->base_href, "/");
  809.         }
  810.         FREE(temp);
  811.         FREE(base);
  812.  
  813.         me->inBASE = TRUE;
  814.         StrAllocCopy(me->node_anchor->content_base, me->base_href);
  815.     }
  816.     break;
  817.  
  818.     case HTML_META:
  819.     if (present)
  820.         LYHandleMETA(me, present, value, (char **)&include);
  821.     break;
  822.  
  823.     case HTML_TITLE:
  824.     HTChunkClear(&me->title);
  825.     break;
  826.  
  827.     case HTML_LINK:
  828. #ifndef DONT_TRACK_INTERNAL_LINKS
  829.     intern_flag = FALSE;
  830. #endif
  831.     if (present && present[HTML_LINK_HREF]) {
  832.         CHECK_FOR_INTERN(value[HTML_LINK_HREF]);
  833.         /*
  834.          *    Prepare to do housekeeping on the reference. - FM
  835.          */
  836.         if (!value[HTML_LINK_HREF]) {
  837.         if (me->inBASE && me->base_href && *me->base_href) {
  838.             StrAllocCopy(href, me->base_href);
  839.         } else {
  840.             StrAllocCopy(href, me->node_anchor->address);
  841.         }
  842.         } else {
  843.         StrAllocCopy(href, value[HTML_LINK_HREF]);
  844.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  845.         }
  846.  
  847.         /*
  848.          *    Check whether a base tag is in effect. - FM
  849.          */
  850.         if ((me->inBASE && *href != '\0' && *href != '#') &&
  851.         (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  852.         *temp != '\0')
  853.         /*
  854.          *  Use reference related to the base.
  855.          */
  856.         StrAllocCopy(href, temp);
  857.         FREE(temp);
  858.  
  859.         /*
  860.          *    Check whether to fill in localhost. - FM
  861.          */
  862.         LYFillLocalFileURL((char **)&href,
  863.                    ((*href != '\0' && *href != '#' &&
  864.                  me->inBASE) ?
  865.                    me->base_href : me->node_anchor->address));
  866.  
  867.         /*
  868.          *    Handle links with a REV attribute. - FM
  869.          */
  870.         if (present &&
  871.         present[HTML_LINK_REV] && value[HTML_LINK_REV]) {
  872.         /*
  873.          *  Handle REV="made" or REV="owner". - LM & FM
  874.          */
  875.         if (!strcasecomp("made", value[HTML_LINK_REV]) ||
  876.             !strcasecomp("owner", value[HTML_LINK_REV])) {
  877.             /*
  878.              *    Load the owner element. - FM
  879.              */
  880.             if (!is_url(href)) {
  881.             temp = HTParse(href,
  882.                        (me->inBASE ?
  883.                      me->base_href : me->node_anchor->address),
  884.                     PARSE_ALL);
  885.             StrAllocCopy(href, temp);
  886.             FREE(temp);
  887.             LYFillLocalFileURL((char **)&href,
  888.                        (me->inBASE ?
  889.                      me->base_href :
  890.                      me->node_anchor->address));
  891.             }
  892.             HTAnchor_setOwner(me->node_anchor, href);
  893.             CTRACE(tfp, "HTML: DOC OWNER '%s' found\n", href);
  894.             FREE(href);
  895.  
  896.             /*
  897.              *    Load the RevTitle element if a TITLE attribute
  898.              *    and value are present. - FM
  899.              */
  900.             if (present && present[HTML_LINK_TITLE] &&
  901.             value[HTML_LINK_TITLE] &&
  902.             *value[HTML_LINK_TITLE] != '\0') {
  903.             StrAllocCopy(title, value[HTML_LINK_TITLE]);
  904.             TRANSLATE_AND_UNESCAPE_ENTITIES(&title, TRUE, FALSE);
  905.             LYTrimHead(title);
  906.             LYTrimTail(title);
  907.             if (*title != '\0')
  908.                 HTAnchor_setRevTitle(me->node_anchor, title);
  909.             FREE(title);
  910.             }
  911.             break;
  912.         }
  913.         }
  914.  
  915.         /*
  916.          *    Handle REL links. - FM
  917.          */
  918.         if (present &&
  919.         present[HTML_LINK_REL] && value[HTML_LINK_REL]) {
  920.         /*
  921.          *  Ignore style sheets, for now. - FM
  922.          */
  923.         if (!strcasecomp(value[HTML_LINK_REL], "StyleSheet") ||
  924.             !strcasecomp(value[HTML_LINK_REL], "Style")) {
  925.             CTRACE(tfp, "HTML: StyleSheet link found.\n");
  926. #ifdef LINKEDSTYLES
  927.             if (href && *href != '\0')
  928.             {
  929.             int res = -999;
  930.             if ((url_type = is_url(href)) == 0 ||
  931.                 (url_type == FILE_URL_TYPE && LYisLocalFile(href))) {
  932.                 if (url_type == FILE_URL_TYPE) {
  933.                 temp = HTParse(href, "", PARSE_PATH+PARSE_PUNCTUATION);
  934.                 HTUnEscape(temp);
  935.                 if (temp && *temp != '\0') {
  936.                     res = style_readFromFile(temp);
  937.                     if (res != 0)
  938.                     StrAllocCopy(href, temp);
  939.                 }
  940.                 FREE(temp);
  941.                 } else {
  942.                 res = style_readFromFile(href);
  943.                 }
  944.             }
  945.             CTRACE(tfp, "CSS: StyleSheet=%s %d\n", href, res);
  946.             if (res == 0)
  947.                 HTAnchor_setStyle (me->node_anchor, href);
  948.             }
  949.             else {
  950.             CTRACE(tfp,
  951.                 "        non-local StyleSheets not yet implemented.\n");
  952.             }
  953. #else
  954.             CTRACE(tfp,
  955.                 "        StyleSheets not yet implemented.\n");
  956. #endif
  957.             FREE(href);
  958.             break;
  959.         }
  960.  
  961.         /*
  962.          *  Ignore anything not registered in the the 28-Mar-95
  963.          *  IETF HTML 3.0 draft and W3C HTML 3.2 draft, or not
  964.          *  appropriate for Lynx banner links in the expired
  965.          *  Maloney and Quin relrev draft.  We'll make this more
  966.          *  efficient when the situation stabilizes, and for now,
  967.          *  we'll treat "Banner" as another toolbar element. - FM
  968.          */
  969.         if (!strcasecomp(value[HTML_LINK_REL], "Home") ||
  970.             !strcasecomp(value[HTML_LINK_REL], "ToC") ||
  971.             !strcasecomp(value[HTML_LINK_REL], "Contents") ||
  972.             !strcasecomp(value[HTML_LINK_REL], "Index") ||
  973.             !strcasecomp(value[HTML_LINK_REL], "Glossary") ||
  974.             !strcasecomp(value[HTML_LINK_REL], "Copyright") ||
  975.             !strcasecomp(value[HTML_LINK_REL], "Up") ||
  976.             !strcasecomp(value[HTML_LINK_REL], "Next") ||
  977.             !strcasecomp(value[HTML_LINK_REL], "Previous") ||
  978.             !strcasecomp(value[HTML_LINK_REL], "Prev") ||
  979.             !strcasecomp(value[HTML_LINK_REL], "Help") ||
  980.             !strcasecomp(value[HTML_LINK_REL], "Search") ||
  981.             !strcasecomp(value[HTML_LINK_REL], "Bookmark") ||
  982.             !strcasecomp(value[HTML_LINK_REL], "Banner") ||
  983.             !strcasecomp(value[HTML_LINK_REL], "Top") ||
  984.             !strcasecomp(value[HTML_LINK_REL], "Origin") ||
  985.             !strcasecomp(value[HTML_LINK_REL], "Navigator") ||
  986.             !strcasecomp(value[HTML_LINK_REL], "Child") ||
  987.             !strcasecomp(value[HTML_LINK_REL], "Disclaimer") ||
  988.             !strcasecomp(value[HTML_LINK_REL], "Sibling") ||
  989.             !strcasecomp(value[HTML_LINK_REL], "Parent") ||
  990.             !strcasecomp(value[HTML_LINK_REL], "Author") ||
  991.             !strcasecomp(value[HTML_LINK_REL], "Editor") ||
  992.             !strcasecomp(value[HTML_LINK_REL], "Publisher") ||
  993.             !strcasecomp(value[HTML_LINK_REL], "Trademark") ||
  994.             !strcasecomp(value[HTML_LINK_REL], "Meta") ||
  995.             !strcasecomp(value[HTML_LINK_REL], "URC") ||
  996.             !strcasecomp(value[HTML_LINK_REL], "Hotlist") ||
  997.             !strcasecomp(value[HTML_LINK_REL], "Begin") ||
  998.             !strcasecomp(value[HTML_LINK_REL], "First") ||
  999.             !strcasecomp(value[HTML_LINK_REL], "End") ||
  1000.             !strcasecomp(value[HTML_LINK_REL], "Last") ||
  1001.             !strcasecomp(value[HTML_LINK_REL], "Pointer") ||
  1002.             !strcasecomp(value[HTML_LINK_REL], "Translation") ||
  1003.             !strcasecomp(value[HTML_LINK_REL], "Definition") ||
  1004.             !strcasecomp(value[HTML_LINK_REL], "Chapter") ||
  1005.             !strcasecomp(value[HTML_LINK_REL], "Documentation") ||
  1006.             !strcasecomp(value[HTML_LINK_REL], "Biblioentry") ||
  1007.             !strcasecomp(value[HTML_LINK_REL], "Bibliography")) {
  1008.             StrAllocCopy(title, value[HTML_LINK_REL]);
  1009.         } else {
  1010.             CTRACE(tfp, "HTML: LINK with REL=\"%s\" ignored.\n",
  1011.                  value[HTML_LINK_REL]);
  1012.             FREE(href);
  1013.             break;
  1014.         }
  1015.         }
  1016.     } else if (present &&
  1017.            present[HTML_LINK_REL] && value[HTML_LINK_REL]) {
  1018.         /*
  1019.          *    If no HREF was specified, handle special REL links
  1020.          *    with self-designated HREFs. - FM
  1021.          */
  1022.         if (!strcasecomp(value[HTML_LINK_REL], "Home")) {
  1023.         StrAllocCopy(href, LynxHome);
  1024.         } else if (!strcasecomp(value[HTML_LINK_REL], "Help")) {
  1025.         StrAllocCopy(href, helpfile);
  1026.         } else if (!strcasecomp(value[HTML_LINK_REL], "Index")) {
  1027.         StrAllocCopy(href, indexfile);
  1028.         } else {
  1029.         CTRACE(tfp, "HTML: LINK with REL=\"%s\" and no HREF ignored.\n",
  1030.                 value[HTML_LINK_REL]);
  1031.         break;
  1032.         }
  1033.         StrAllocCopy(title, value[HTML_LINK_REL]);
  1034.     }
  1035.     if (href) {
  1036.         /*
  1037.          *    Create a title (link name) from the TITLE value,
  1038.          *    if present, or default to the REL value that was
  1039.          *    loaded into title. - FM
  1040.          */
  1041.         if (present && present[HTML_LINK_TITLE] &&
  1042.         value[HTML_LINK_TITLE] && *value[HTML_LINK_TITLE] != '\0') {
  1043.         StrAllocCopy(title, value[HTML_LINK_TITLE]);
  1044.         TRANSLATE_AND_UNESCAPE_ENTITIES(&title, TRUE, FALSE);
  1045.         LYTrimHead(title);
  1046.         LYTrimTail(title);
  1047.         }
  1048.         if (!(title && *title)) {
  1049.         FREE(href);
  1050.         FREE(title);
  1051.         break;
  1052.         }
  1053.  
  1054.         if (me->inA) {
  1055.         /*
  1056.          *  Ugh!  The LINK tag, which is a HEAD element,
  1057.          *  is in an Anchor, which is BODY element.  All
  1058.          *  we can do is close the Anchor and cross our
  1059.          *  fingers. - FM
  1060.          */
  1061.         SET_SKIP_STACK(HTML_A);
  1062.         HTML_end_element(me, HTML_A, (char **)&include);
  1063.         }
  1064.  
  1065.         /*
  1066.          *    Create anchors for the links that simulate
  1067.          *    a toolbar. - FM
  1068.          */
  1069.         me->CurrentA = HTAnchor_findChildAndLink(
  1070.                 me->node_anchor,    /* Parent */
  1071.                 NULL,            /* Tag */
  1072.                 href,            /* Addresss */
  1073.                 INTERN_LT);        /* Type */
  1074.         if ((dest = HTAnchor_parent(
  1075.                 HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
  1076.                       )) != NULL) {
  1077.         if (!HTAnchor_title(dest))
  1078.             HTAnchor_setTitle(dest, title);
  1079.         dest = NULL;
  1080.         if (present[HTML_LINK_CHARSET] &&
  1081.             value[HTML_LINK_CHARSET] && *value[HTML_LINK_CHARSET] != '\0') {
  1082.             dest_char_set = UCGetLYhndl_byMIME(value[HTML_LINK_CHARSET]);
  1083.             if (dest_char_set < 0)
  1084.             dest_char_set = UCLYhndl_for_unrec;
  1085.         }
  1086.         if (dest && dest_char_set >= 0)
  1087.             HTAnchor_setUCInfoStage(dest, dest_char_set,
  1088.                         UCT_STAGE_PARSER,
  1089.                         UCT_SETBY_LINK);
  1090.         dest_char_set = -1;
  1091.         }
  1092.         UPDATE_STYLE;
  1093.         if (!HText_hasToolbar(me->text) &&
  1094.         (ID_A = HTAnchor_findChildAndLink(
  1095.                     me->node_anchor,    /* Parent */
  1096.                     LYToolbarName,        /* Tag */
  1097.                     NULL,            /* Addresss */
  1098.                     (HTLinkType*)0))) {    /* Type */
  1099.         HText_appendCharacter(me->text, '#');
  1100.         HText_setLastChar(me->text, ' ');  /* absorb white space */
  1101.         HText_beginAnchor(me->text, me->inUnderline, ID_A);
  1102.         HText_endAnchor(me->text, 0);
  1103.         HText_setToolbar(me->text);
  1104.         }
  1105.         HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
  1106.         if (me->inBoldH == FALSE)
  1107.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  1108. #ifdef USE_COLOR_STYLE
  1109.         if (present && present[HTML_LINK_CLASS] &&
  1110.         value && *value[HTML_LINK_CLASS]!='\0')
  1111.         {
  1112.         char tmp[1024];
  1113.         sprintf(tmp, "link.%s.%s.%s", value[HTML_LINK_CLASS], title, value[HTML_LINK_CLASS]);
  1114.         CTRACE(tfp, "CSSTRIM:link=%s\n", tmp);
  1115.  
  1116.         HText_characterStyle(me->text, hash_code(tmp), 1);
  1117.         HTML_put_string(me, title);
  1118.         HTML_put_string(me, " (");
  1119.         HTML_put_string(me, value[HTML_LINK_CLASS]);
  1120.         HTML_put_string(me, ")");
  1121.         HText_characterStyle(me->text, hash_code(tmp), 0);
  1122.         }
  1123.         else
  1124. #endif
  1125.         HTML_put_string(me, title);
  1126.         if (me->inBoldH == FALSE)
  1127.         HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  1128.         HText_endAnchor(me->text, 0);
  1129.     }
  1130.     FREE(href);
  1131.     FREE(title);
  1132.     break;
  1133.  
  1134.     case HTML_ISINDEX:
  1135.     if (((present)) &&
  1136.         ((present[HTML_ISINDEX_HREF] && value[HTML_ISINDEX_HREF]) ||
  1137.          (present[HTML_ISINDEX_ACTION] && value[HTML_ISINDEX_ACTION]))) {
  1138.         char * action = NULL;
  1139.         char * isindex_href = NULL;
  1140.  
  1141.         /*
  1142.          *    Lynx was supporting ACTION, which never made it into
  1143.          *    the HTML 2.0 specs.  HTML 3.0 uses HREF, so we'll
  1144.          *    use that too, but allow use of ACTION as an alternate
  1145.          *    until people have fully switched over. - FM
  1146.          */
  1147.         if (present[HTML_ISINDEX_HREF] && value[HTML_ISINDEX_HREF])
  1148.         StrAllocCopy(isindex_href, value[HTML_ISINDEX_HREF]);
  1149.         else
  1150.         StrAllocCopy(isindex_href, value[HTML_ISINDEX_ACTION]);
  1151.         url_type = LYLegitimizeHREF(me, (char**)&isindex_href,
  1152.                     TRUE, TRUE);
  1153.  
  1154.         /*
  1155.          *    Check whether a base tag is in effect.
  1156.          */
  1157.         if (me->inBASE && *isindex_href != '\0' && *isindex_href != '#')
  1158.         action = HTParse(isindex_href, me->base_href, PARSE_ALL);
  1159.         if (!(action && *action))
  1160.         action = HTParse(isindex_href,
  1161.                  me->node_anchor->address, PARSE_ALL);
  1162.         FREE(isindex_href);
  1163.  
  1164.         if (action && *action) {
  1165.         HTAnchor_setIndex(me->node_anchor, action);
  1166.         } else {
  1167.         HTAnchor_setIndex(me->node_anchor, me->node_anchor->address);
  1168.         }
  1169.         FREE(action);
  1170.  
  1171.     } else {
  1172.         if (me->inBASE)
  1173.         /*
  1174.          *  Use base.
  1175.          */
  1176.         HTAnchor_setIndex(me->node_anchor, me->base_href);
  1177.         else
  1178.         /*
  1179.          *  Use index's address.
  1180.          */
  1181.         HTAnchor_setIndex(me->node_anchor, me->node_anchor->address);
  1182.     }
  1183.     /*
  1184.      *  Support HTML 3.0 PROMPT attribute. - FM
  1185.      */
  1186.     if (present &&
  1187.         present[HTML_ISINDEX_PROMPT] &&
  1188.         value[HTML_ISINDEX_PROMPT] && *value[HTML_ISINDEX_PROMPT]) {
  1189.         StrAllocCopy(temp, value[HTML_ISINDEX_PROMPT]);
  1190.         TRANSLATE_AND_UNESCAPE_ENTITIES(&temp, TRUE, FALSE);
  1191.         LYTrimHead(temp);
  1192.         LYTrimTail(temp);
  1193.         if (*temp != '\0') {
  1194.         StrAllocCat(temp, " ");
  1195.         HTAnchor_setPrompt(me->node_anchor, temp);
  1196.         } else {
  1197.         HTAnchor_setPrompt(me->node_anchor,
  1198.                    "Enter a database query: ");
  1199.         }
  1200.         FREE(temp);
  1201.     } else {
  1202.         HTAnchor_setPrompt(me->node_anchor, "Enter a database query: ");
  1203.     }
  1204.     break;
  1205.  
  1206.     case HTML_NEXTID:
  1207.     /* if (present && present[NEXTID_N] && value[NEXTID_N])
  1208.         HText_setNextId(me->text, atoi(value[NEXTID_N])); */
  1209.     break;
  1210.  
  1211.     case HTML_STYLE:
  1212.     /*
  1213.      *  We're getting it as Literal text, which, for now,
  1214.      *  we'll just ignore. - FM
  1215.      */
  1216.     HTChunkClear(&me->style_block);
  1217.     break;
  1218.  
  1219.     case HTML_SCRIPT:
  1220.     /*
  1221.      *  We're getting it as Literal text, which, for now,
  1222.      *  we'll just ignore. - FM
  1223.      */
  1224.     HTChunkClear(&me->script);
  1225.     break;
  1226.  
  1227.     case HTML_BODY:
  1228.     CHECK_ID(HTML_BODY_ID);
  1229.     if (HText_hasToolbar(me->text))
  1230.         HText_appendParagraph(me->text);
  1231.     break;
  1232.  
  1233.     case HTML_FRAMESET:
  1234.     break;
  1235.  
  1236.     case HTML_FRAME:
  1237.     if (present && present[HTML_FRAME_NAME] &&
  1238.         value[HTML_FRAME_NAME] && *value[HTML_FRAME_NAME]) {
  1239.         StrAllocCopy(id_string, value[HTML_FRAME_NAME]);
  1240.         TRANSLATE_AND_UNESCAPE_ENTITIES(&id_string, TRUE, FALSE);
  1241.         LYTrimHead(id_string);
  1242.         LYTrimTail(id_string);
  1243.     }
  1244.     if (present && present[HTML_FRAME_SRC] &&
  1245.         value[HTML_FRAME_SRC] && *value[HTML_FRAME_SRC] != '\0') {
  1246.         StrAllocCopy(href, value[HTML_FRAME_SRC]);
  1247.         CHECK_FOR_INTERN(href);
  1248.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  1249.  
  1250.         /*
  1251.          *    Check whether a base tag is in effect. - FM
  1252.          */
  1253.         if ((me->inBASE && *href != '\0' && *href != '#') &&
  1254.         (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  1255.         *temp != '\0')
  1256.         /*
  1257.          *  Use reference related to the base.
  1258.          */
  1259.         StrAllocCopy(href, temp);
  1260.         FREE(temp);
  1261.  
  1262.         /*
  1263.          *    Check whether to fill in localhost. - FM
  1264.          */
  1265.         LYFillLocalFileURL((char **)&href,
  1266.                    ((*href != '\0' && *href != '#' &&
  1267.                  me->inBASE) ?
  1268.                    me->base_href : me->node_anchor->address));
  1269.  
  1270.         if (me->inA) {
  1271.         SET_SKIP_STACK(HTML_A);
  1272.         HTML_end_element(me, HTML_A, (char **)&include);
  1273.         }
  1274.         me->CurrentA = HTAnchor_findChildAndLink(
  1275.                 me->node_anchor,    /* Parent */
  1276.                 NULL,            /* Tag */
  1277.                 href,            /* Addresss */
  1278.                 INTERN_LT);        /* Type */
  1279.         LYEnsureSingleSpace(me);
  1280.         if (me->inUnderline == FALSE)
  1281.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  1282.         HTML_put_string(me, "FRAME:");
  1283.         if (me->inUnderline == FALSE)
  1284.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  1285.         HTML_put_character(me, ' ');
  1286.         me->in_word = NO;
  1287.         CHECK_ID(HTML_FRAME_ID);
  1288.         HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
  1289.         if (me->inBoldH == FALSE)
  1290.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  1291.         HTML_put_string(me, (id_string ? id_string : href));
  1292.         FREE(href);
  1293.         if (me->inBoldH == FALSE)
  1294.         HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  1295.         HText_endAnchor(me->text, 0);
  1296.         LYEnsureSingleSpace(me);
  1297.     } else {
  1298.         CHECK_ID(HTML_FRAME_ID);
  1299.     }
  1300.     FREE(id_string);
  1301.     break;
  1302.  
  1303.     case HTML_NOFRAMES:
  1304.     LYEnsureDoubleSpace(me);
  1305.     LYResetParagraphAlignment(me);
  1306.     break;
  1307.  
  1308.     case HTML_IFRAME:
  1309.     if (present && present[HTML_IFRAME_NAME] &&
  1310.         value[HTML_IFRAME_NAME] && *value[HTML_IFRAME_NAME]) {
  1311.         StrAllocCopy(id_string, value[HTML_IFRAME_NAME]);
  1312.         TRANSLATE_AND_UNESCAPE_ENTITIES(&id_string, TRUE, FALSE);
  1313.         LYTrimHead(id_string);
  1314.         LYTrimTail(id_string);
  1315.     }
  1316.     if (present && present[HTML_IFRAME_SRC] &&
  1317.         value[HTML_IFRAME_SRC] && *value[HTML_IFRAME_SRC] != '\0') {
  1318.         StrAllocCopy(href, value[HTML_IFRAME_SRC]);
  1319.         CHECK_FOR_INTERN(href);
  1320.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  1321.  
  1322.         /*
  1323.          *    Check whether a base tag is in effect. - FM
  1324.          */
  1325.         if ((me->inBASE && *href != '\0' && *href != '#') &&
  1326.         (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  1327.         *temp != '\0')
  1328.         /*
  1329.          *  Use reference related to the base.
  1330.          */
  1331.         StrAllocCopy(href, temp);
  1332.         FREE(temp);
  1333.  
  1334.         /*
  1335.          *    Check whether to fill in localhost. - FM
  1336.          */
  1337.         LYFillLocalFileURL((char **)&href,
  1338.                    ((*href != '\0' && *href != '#' &&
  1339.                  me->inBASE) ?
  1340.                    me->base_href : me->node_anchor->address));
  1341.  
  1342.         if (me->inA)
  1343.         HTML_end_element(me, HTML_A, (char **)&include);
  1344.         me->CurrentA = HTAnchor_findChildAndLink(
  1345.                 me->node_anchor,    /* Parent */
  1346.                 NULL,            /* Tag */
  1347.                 href,            /* Addresss */
  1348.                 INTERN_LT);        /* Type */
  1349.         LYEnsureDoubleSpace(me);
  1350.         LYResetParagraphAlignment(me);
  1351.         if (me->inUnderline == FALSE)
  1352.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  1353.         HTML_put_string(me, "IFRAME:");
  1354.         if (me->inUnderline == FALSE)
  1355.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  1356.         HTML_put_character(me, ' ');
  1357.         me->in_word = NO;
  1358.         CHECK_ID(HTML_IFRAME_ID);
  1359.         HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
  1360.         if (me->inBoldH == FALSE)
  1361.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  1362.         HTML_put_string(me, (id_string ? id_string : href));
  1363.         FREE(href);
  1364.         if (me->inBoldH == FALSE)
  1365.         HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  1366.         HText_endAnchor(me->text, 0);
  1367.         LYEnsureSingleSpace(me);
  1368.     } else {
  1369.         CHECK_ID(HTML_IFRAME_ID);
  1370.     }
  1371.     FREE(id_string);
  1372.     break;
  1373.  
  1374.     case HTML_BANNER:
  1375.     case HTML_MARQUEE:
  1376.     change_paragraph_style(me, styles[HTML_BANNER]);
  1377.     UPDATE_STYLE;
  1378.     if (me->sp->tag_number == ElementNumber)
  1379.         LYEnsureDoubleSpace(me);
  1380.     /*
  1381.      *  Treat this as a toolbar if we don't have one
  1382.      *  yet, and we are in the first half of the
  1383.      *  first page. - FM
  1384.      */
  1385.     if ((!HText_hasToolbar(me->text) &&
  1386.          HText_getLines(me->text) < (display_lines/2)) &&
  1387.         (ID_A = HTAnchor_findChildAndLink(
  1388.                     me->node_anchor,    /* Parent */
  1389.                     LYToolbarName,        /* Tag */
  1390.                     NULL,            /* Addresss */
  1391.                     (HTLinkType*)0))) {    /* Type */
  1392.         HText_beginAnchor(me->text, me->inUnderline, ID_A);
  1393.         HText_endAnchor(me->text, 0);
  1394.         HText_setToolbar(me->text);
  1395.     }
  1396.     CHECK_ID(HTML_GEN_ID);
  1397.     break;
  1398.  
  1399.     case HTML_CENTER:
  1400.     case HTML_DIV:
  1401.     if (me->Division_Level < (MAX_NESTING - 1)) {
  1402.         me->Division_Level++;
  1403.     } else {
  1404.         CTRACE(tfp,
  1405.         "HTML: ****** Maximum nesting of %d divisions exceeded!\n",
  1406.         MAX_NESTING);
  1407.     }
  1408.     if (ElementNumber == HTML_CENTER) {
  1409.         me->DivisionAlignments[me->Division_Level] = HT_CENTER;
  1410.         change_paragraph_style(me, styles[HTML_DCENTER]);
  1411.         UPDATE_STYLE;
  1412.         me->current_default_alignment = styles[HTML_DCENTER]->alignment;
  1413.     } else if (present && present[HTML_DIV_ALIGN] &&
  1414.            value[HTML_DIV_ALIGN] && *value[HTML_DIV_ALIGN]) {
  1415.         if (!strcasecomp(value[HTML_DIV_ALIGN], "center")) {
  1416.         me->DivisionAlignments[me->Division_Level] = HT_CENTER;
  1417.         change_paragraph_style(me, styles[HTML_DCENTER]);
  1418.         UPDATE_STYLE;
  1419.         me->current_default_alignment = styles[HTML_DCENTER]->alignment;
  1420.         } else if (!strcasecomp(value[HTML_DIV_ALIGN], "right")) {
  1421.         me->DivisionAlignments[me->Division_Level] = HT_RIGHT;
  1422.         change_paragraph_style(me, styles[HTML_DRIGHT]);
  1423.         UPDATE_STYLE;
  1424.         me->current_default_alignment = styles[HTML_DRIGHT]->alignment;
  1425.         } else {
  1426.         me->DivisionAlignments[me->Division_Level] = HT_LEFT;
  1427.         change_paragraph_style(me, styles[HTML_DLEFT]);
  1428.         UPDATE_STYLE;
  1429.         me->current_default_alignment = styles[HTML_DLEFT]->alignment;
  1430.         }
  1431.     } else {
  1432.         me->DivisionAlignments[me->Division_Level] = HT_LEFT;
  1433.         change_paragraph_style(me, styles[HTML_DLEFT]);
  1434.         UPDATE_STYLE;
  1435.         me->current_default_alignment = styles[HTML_DLEFT]->alignment;
  1436.     }
  1437.     CHECK_ID(HTML_DIV_ID);
  1438.     break;
  1439.  
  1440.     case HTML_H1:
  1441.     case HTML_H2:
  1442.     case HTML_H3:
  1443.     case HTML_H4:
  1444.     case HTML_H5:
  1445.     case HTML_H6:
  1446.     /*
  1447.      *  Close the previous style if not done by HTML doc.
  1448.      *  Added to get rid of core dumps in BAD HTML on the net.
  1449.      *        GAB 07-07-94
  1450.      *  But then again, these are actually allowed to nest.  I guess
  1451.      *  I have to depend on the HTML writers correct style.
  1452.      *        GAB 07-12-94
  1453.     if (i_prior_style != -1) {
  1454.         HTML_end_element(me, i_prior_style);
  1455.     }
  1456.     i_prior_style = ElementNumber;
  1457.      */
  1458.  
  1459.     /*
  1460.      *  Check whether we have an H# in a list,
  1461.      *  and if so, treat it as an LH. - FM
  1462.      */
  1463.     if ((me->List_Nesting_Level >= 0) &&
  1464.         (me->sp[0].tag_number == HTML_UL ||
  1465.          me->sp[0].tag_number == HTML_OL ||
  1466.          me->sp[0].tag_number == HTML_MENU ||
  1467.          me->sp[0].tag_number == HTML_DIR)) {
  1468.         if (HTML_dtd.tags[HTML_LH].contents == SGML_EMPTY) {
  1469.         ElementNumber = HTML_LH;
  1470.         } else {
  1471.         me->new_style = me->sp[0].style;
  1472.         ElementNumber = me->sp[0].tag_number;
  1473.         UPDATE_STYLE;
  1474.         }
  1475.         /*
  1476.          *    Some authors use H# headers as a substitute for
  1477.          *    FONT, so check if this one immediately followed
  1478.          *    an LI.    If so, both me->inP and me->in_word will
  1479.          *    be FALSE (though the line might not be empty due
  1480.          *    to a bullet and/or nbsp) and we can assume it is
  1481.          *    just for a FONT change.  We thus will not create
  1482.          *    another line break nor add to the current left
  1483.          *    indentation. - FM
  1484.          */
  1485.         if (!(me->inP == FALSE && me->in_word == NO)) {
  1486.         HText_appendParagraph(me->text);
  1487.         HTML_put_character(me, HT_NON_BREAK_SPACE);
  1488.         HText_setLastChar(me->text, ' ');
  1489.         me->in_word = NO;
  1490.         me->inP = FALSE;
  1491.         }
  1492.         CHECK_ID(HTML_H_ID);
  1493.         break;
  1494.     }
  1495.  
  1496.     if (present && present[HTML_H_ALIGN] &&
  1497.         value[HTML_H_ALIGN] && *value[HTML_H_ALIGN]) {
  1498.         if (!strcasecomp(value[HTML_H_ALIGN], "center"))
  1499.         change_paragraph_style(me, styles[HTML_HCENTER]);
  1500.         else if (!strcasecomp(value[HTML_H_ALIGN], "right"))
  1501.         change_paragraph_style(me, styles[HTML_HRIGHT]);
  1502.         else if (!strcasecomp(value[HTML_H_ALIGN], "left") ||
  1503.              !strcasecomp(value[HTML_H_ALIGN], "justify"))
  1504.         change_paragraph_style(me, styles[HTML_HLEFT]);
  1505.         else
  1506.         change_paragraph_style(me, styles[ElementNumber]);
  1507.     } else if (me->Division_Level >= 0) {
  1508.         if (me->DivisionAlignments[me->Division_Level] == HT_CENTER) {
  1509.         change_paragraph_style(me, styles[HTML_HCENTER]);
  1510.         } else if (me->DivisionAlignments[me->Division_Level] == HT_LEFT) {
  1511.         change_paragraph_style(me, styles[HTML_HLEFT]);
  1512.         } else if (me->DivisionAlignments[me->Division_Level] == HT_RIGHT) {
  1513.         change_paragraph_style(me, styles[HTML_HRIGHT]);
  1514.         }
  1515.     } else {
  1516.         change_paragraph_style(me, styles[ElementNumber]);
  1517.     }
  1518.     UPDATE_STYLE;
  1519.     CHECK_ID(HTML_H_ID);
  1520.  
  1521.     if ((bold_headers == TRUE ||
  1522.          (ElementNumber == HTML_H1 && bold_H1 == TRUE)) &&
  1523.         (styles[ElementNumber]->font&HT_BOLD)) {
  1524.         if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
  1525.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  1526.         }
  1527.         me->inBoldH = TRUE;
  1528.     }
  1529.     break;
  1530.  
  1531.     case HTML_P:
  1532.     LYHandleP(me, present, value, (char **)&include, TRUE);
  1533.     break;
  1534.  
  1535.     case HTML_BR:
  1536.     UPDATE_STYLE;
  1537.     CHECK_ID(HTML_GEN_ID);
  1538.     if ((LYCollapseBRs == FALSE) ||
  1539.         HText_LastLineSize(me->text, FALSE)) {
  1540.         HText_setLastChar(me->text, ' ');  /* absorb white space */
  1541.         HText_appendCharacter(me->text, '\r');
  1542.     }
  1543.     me->in_word = NO;
  1544.     me->inP = FALSE;
  1545.     break;
  1546.  
  1547.     case HTML_WBR:
  1548.     UPDATE_STYLE;
  1549.     CHECK_ID(HTML_GEN_ID);
  1550.     HText_setBreakPoint(me->text);
  1551.     break;
  1552.  
  1553.     case HTML_HY:
  1554.     case HTML_SHY:
  1555.     UPDATE_STYLE;
  1556.     CHECK_ID(HTML_GEN_ID);
  1557.     HText_appendCharacter(me->text, LY_SOFT_HYPHEN);
  1558.     break;
  1559.  
  1560.     case HTML_HR:
  1561.     {
  1562.         int width;
  1563.  
  1564.         /*
  1565.          *    Start a new line only if we had printable
  1566.          *    characters following the previous newline,
  1567.          *    or remove the previous line if both it and
  1568.          *    the last line are blank. - FM
  1569.          */
  1570.         UPDATE_STYLE;
  1571.         if (HText_LastLineSize(me->text, FALSE)) {
  1572.         HText_setLastChar(me->text, ' ');  /* absorb white space */
  1573.         HText_appendCharacter(me->text, '\r');
  1574.         } else if (!HText_PreviousLineSize(me->text, FALSE)) {
  1575.         HText_RemovePreviousLine(me->text);
  1576.         }
  1577.         me->in_word = NO;
  1578.         me->inP = FALSE;
  1579.  
  1580.         /*
  1581.          *    Add an ID link if needed. - FM
  1582.          */
  1583.         CHECK_ID(HTML_HR_ID);
  1584.  
  1585.        /*
  1586.         *  Center lines within the current margins, if
  1587.         *  a right or left ALIGNment is not specified.
  1588.         *  If WIDTH="#%" is given and not garbage,
  1589.         *  use that to calculate the width, otherwise
  1590.         *  use the default width. - FM
  1591.         */
  1592.         if (present && present[HTML_HR_ALIGN] && value[HTML_HR_ALIGN]) {
  1593.         if (!strcasecomp(value[HTML_HR_ALIGN], "right")) {
  1594.             me->sp->style->alignment = HT_RIGHT;
  1595.         } else if (!strcasecomp(value[HTML_HR_ALIGN], "left")) {
  1596.             me->sp->style->alignment = HT_LEFT;
  1597.         } else {
  1598.             me->sp->style->alignment = HT_CENTER;
  1599.         }
  1600.         } else {
  1601.         me->sp->style->alignment = HT_CENTER;
  1602.         }
  1603.         width = LYcols - 1 -
  1604.             me->new_style->leftIndent - me->new_style->rightIndent;
  1605.         if (present && present[HTML_HR_WIDTH] && value[HTML_HR_WIDTH] &&
  1606.         isdigit(*value[HTML_HR_WIDTH]) &&
  1607.         value[HTML_HR_WIDTH][strlen(value[HTML_HR_WIDTH])-1] == '%') {
  1608.         char *percent = NULL;
  1609.         int Percent, Width;
  1610.         StrAllocCopy(percent, value[HTML_HR_WIDTH]);
  1611.         percent[strlen(percent)-1] = '\0';
  1612.         Percent = atoi(percent);
  1613.         if (Percent > 100 || Percent < 1)
  1614.             width -= 5;
  1615.         else {
  1616.             Width = (width * Percent) / 100;
  1617.             if (Width < 1)
  1618.             width = 1;
  1619.             else
  1620.             width = Width;
  1621.         }
  1622.         FREE(percent);
  1623.         } else {
  1624.         width -= 5;
  1625.         }
  1626.         for (i = 0; i < width; i++)
  1627.         HTML_put_character(me, '_');
  1628.         HText_appendCharacter(me->text, '\r');
  1629.         me->in_word = NO;
  1630.         me->inP = FALSE;
  1631.  
  1632.         /*
  1633.          *    Reset the alignment appropriately
  1634.          *    for the division and/or block. - FM
  1635.          */
  1636.         if (me->List_Nesting_Level < 0 &&
  1637.         me->Division_Level >= 0) {
  1638.         me->sp->style->alignment =
  1639.                 me->DivisionAlignments[me->Division_Level];
  1640.         } else if (!strcmp(me->sp->style->name, "HeadingCenter") ||
  1641.                !strcmp(me->sp->style->name, "Heading1")) {
  1642.         me->sp->style->alignment = HT_CENTER;
  1643.         } else if (!strcmp(me->sp->style->name, "HeadingRight")) {
  1644.         me->sp->style->alignment = HT_RIGHT;
  1645.         } else {
  1646.         me->sp->style->alignment = HT_LEFT;
  1647.         }
  1648.  
  1649.         /*
  1650.          *    Add a blank line and set the second line
  1651.          *    indentation for lists and addresses, or a
  1652.          *    paragraph separator for other blocks. - FM
  1653.          */
  1654.         if (me->List_Nesting_Level >= 0 ||
  1655.         me->sp[0].tag_number == HTML_ADDRESS) {
  1656.         HText_setLastChar(me->text, ' ');  /* absorb white space */
  1657.         HText_appendCharacter(me->text, '\r');
  1658.         } else {
  1659.         HText_appendParagraph(me->text);
  1660.         }
  1661.     }
  1662.     break;
  1663.  
  1664.     case HTML_TAB:
  1665.     if (!present) { /* Bad tag.  Must have at least one attribute. - FM */
  1666.         CTRACE(tfp, "HTML: TAB tag has no attributes. Ignored.\n");
  1667.         break;
  1668.     }
  1669.     UPDATE_STYLE;
  1670.  
  1671.     if (present[HTML_TAB_ALIGN] && value[HTML_TAB_ALIGN] &&
  1672.         (strcasecomp(value[HTML_TAB_ALIGN], "left") ||
  1673.          !(present[HTML_TAB_TO] || present[HTML_TAB_INDENT]))) {
  1674.         /*
  1675.          *    Just ensure a collapsible space, until we have
  1676.          *    the ALIGN and DP attributes implemented. - FM
  1677.          */
  1678.         HTML_put_character(me, ' ');
  1679.         CTRACE(tfp, "HTML: ALIGN not 'left'. Using space instead of TAB.\n");
  1680.  
  1681.     } else if (!LYoverride_default_alignment(me) &&
  1682.            me->current_default_alignment != HT_LEFT) {
  1683.         /*
  1684.          *    Just ensure a collapsible space, until we
  1685.          *    can replace HText_getCurrentColumn() in
  1686.          *    GridText.c with code which doesn't require
  1687.          *    that the alignment be HT_LEFT. - FM
  1688.          */
  1689.         HTML_put_character(me, ' ');
  1690.         CTRACE(tfp, "HTML: Not HT_LEFT. Using space instead of TAB.\n");
  1691.  
  1692.     } else if ((present[HTML_TAB_TO] &&
  1693.             value[HTML_TAB_TO] && *value[HTML_TAB_TO]) ||
  1694.            (present[HTML_TAB_INDENT] &&
  1695.             value[HTML_TAB_INDENT] &&
  1696.             isdigit(*value[HTML_TAB_INDENT]))) {
  1697.         int column, target = -1;
  1698.         int enval = 2;
  1699.  
  1700.         column = HText_getCurrentColumn(me->text);
  1701.         if (present[HTML_TAB_TO]) {
  1702.         /*
  1703.          *  TO has priority over INDENT if both are present. - FM
  1704.          */
  1705.         StrAllocCopy(temp, value[HTML_TAB_TO]);
  1706.         TRANSLATE_AND_UNESCAPE_TO_STD(&temp);
  1707.         if (*temp) {
  1708.             target = HText_getTabIDColumn(me->text, temp);
  1709.         }
  1710.         } else if (!(temp && *temp) && present[HTML_TAB_INDENT] &&
  1711.                value[HTML_TAB_INDENT] &&
  1712.                isdigit(*value[HTML_TAB_INDENT])) {
  1713.         /*
  1714.          *  The INDENT value is in "en" (enval per column) units.
  1715.          *  Divide it by enval, rounding odd values up. - FM
  1716.          */
  1717.         target =
  1718.            (int)(((1.0 * atoi(value[HTML_TAB_INDENT]))/enval)+(0.5));
  1719.         }
  1720.         FREE(temp);
  1721.         /*
  1722.          *    If we are being directed to a column too far to the left
  1723.          *    or right, just add a collapsible space, otherwise, add the
  1724.          *    appropriate number of spaces. - FM
  1725.          */
  1726.         if (target < column ||
  1727.         target > HText_getMaximumColumn(me->text)) {
  1728.         HTML_put_character(me, ' ');
  1729.         CTRACE(tfp, "HTML: Column out of bounds. Using space instead of TAB.\n");
  1730.         } else {
  1731.         for (i = column; i < target; i++)
  1732.             HText_appendCharacter(me->text, ' ');
  1733.         HText_setLastChar(me->text, ' ');  /* absorb white space */
  1734.         }
  1735.     }
  1736.     me->in_word = NO;
  1737.  
  1738.     /*
  1739.      *  If we have an ID attribute, save it together
  1740.      *  with the value of the column we've reached. - FM
  1741.      */
  1742.     if (present[HTML_TAB_ID] &&
  1743.         value[HTML_TAB_ID] && *value[HTML_TAB_ID]) {
  1744.         StrAllocCopy(temp, value[HTML_TAB_ID]);
  1745.         TRANSLATE_AND_UNESCAPE_TO_STD(&temp);
  1746.         if (*temp)
  1747.         HText_setTabID(me->text, temp);
  1748.         FREE(temp);
  1749.     }
  1750.     break;
  1751.  
  1752.     case HTML_BASEFONT:
  1753.     break;
  1754.  
  1755.     case HTML_FONT:
  1756.  
  1757.     /*
  1758.      *  FONT *may* have been declared SGML_EMPTY in HTMLDTD.c, and
  1759.      *  SGML_character() in SGML.c *may* check for a FONT end
  1760.      *  tag to call HTML_end_element() directly (with a
  1761.      *  check in that to bypass decrementing of the HTML
  1762.      *  parser's stack).  Or this may have been really a </FONT>
  1763.      *  end tag, for which some incarnations of SGML.c would fake
  1764.      *  a <FONT> start tag instead. - fm & kw
  1765.      *
  1766.      *  But if we have an open FONT, DON'T close that one now,
  1767.      *  since FONT tags can be legally nested AFAIK, and Lynx
  1768.      *  currently doesn't do anything with them anyway... - kw
  1769.      */
  1770. #ifdef NOTUSED_FOTEMODS
  1771.     if (me->inFONT == TRUE)
  1772.         HTML_end_element(me, HTML_FONT, (char **)&include);
  1773. #endif /* NOTUSED_FOTEMODS */
  1774.  
  1775.     /*
  1776.      *  Set flag to know we are in a FONT container, and
  1777.      *  add code to do something about it, someday. - FM
  1778.      */
  1779.     me->inFONT = TRUE;
  1780.     break;
  1781.  
  1782.     case HTML_B:            /* Physical character highlighting */
  1783.     case HTML_BLINK:
  1784.     case HTML_I:
  1785.     case HTML_U:
  1786.  
  1787.     case HTML_CITE:            /* Logical character highlighting */
  1788.     case HTML_EM:
  1789.     case HTML_STRONG:
  1790.     UPDATE_STYLE;
  1791.     me->Underline_Level++;
  1792.     CHECK_ID(HTML_GEN_ID);
  1793.     /*
  1794.      *  Ignore this if inside of a bold anchor or header.
  1795.      *  Can't display both underline and bold at same time.
  1796.      */
  1797.     if (me->inBoldA == TRUE || me->inBoldH == TRUE) {
  1798.         CTRACE(tfp, "Underline Level is %d\n", me->Underline_Level);
  1799.         break;
  1800.     }
  1801.     if (me->inUnderline == FALSE) {
  1802.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  1803.         me->inUnderline = TRUE;
  1804.         CTRACE(tfp,"Beginning underline\n");
  1805.     } else {
  1806.         CTRACE(tfp,"Underline Level is %d\n", me->Underline_Level);
  1807.     }
  1808.     break;
  1809.  
  1810.     case HTML_ABBREV:    /* Miscellaneous character containers */
  1811.     case HTML_ACRONYM:
  1812.     case HTML_AU:
  1813.     case HTML_AUTHOR:
  1814.     case HTML_BIG:
  1815.     case HTML_CODE:
  1816.     case HTML_DFN:
  1817.     case HTML_KBD:
  1818.     case HTML_SAMP:
  1819.     case HTML_SMALL:
  1820.     case HTML_SUB:
  1821.     case HTML_SUP:
  1822.     case HTML_TT:
  1823.     case HTML_VAR:
  1824.     CHECK_ID(HTML_GEN_ID);
  1825.     break; /* ignore */
  1826.  
  1827.     case HTML_DEL:
  1828.     case HTML_S:
  1829.     case HTML_STRIKE:
  1830.     CHECK_ID(HTML_GEN_ID);
  1831.     if (me->inUnderline == FALSE)
  1832.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  1833.     HTML_put_string(me, "[DEL:");
  1834.     if (me->inUnderline == FALSE)
  1835.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  1836.     HTML_put_character(me, ' ');
  1837.     me->in_word = NO;
  1838.     break;
  1839.  
  1840.     case HTML_INS:
  1841.     CHECK_ID(HTML_GEN_ID);
  1842.     if (me->inUnderline == FALSE)
  1843.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  1844.     HTML_put_string(me, "[INS:");
  1845.     if (me->inUnderline == FALSE)
  1846.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  1847.     HTML_put_character(me, ' ');
  1848.     me->in_word = NO;
  1849.     break;
  1850.  
  1851.     case HTML_Q:
  1852.     CHECK_ID(HTML_GEN_ID);
  1853.     /*
  1854.      *  Should check LANG and/or DIR attributes, and the
  1855.      *  me->node_anchor->charset and/or yet to be added
  1856.      *  structure elements, to determine whether we should
  1857.      *  use chevrons, but for now we'll always use double-
  1858.      *  or single-quotes. - FM
  1859.      */
  1860.     if (!(me->Quote_Level & 1))
  1861.         HTML_put_character(me, '"');
  1862.     else
  1863.         HTML_put_character(me, '`');
  1864.     me->Quote_Level++;
  1865.     break;
  1866.  
  1867.     case HTML_PRE:                /* Formatted text */
  1868.     /*
  1869.     **  Set our inPRE flag to FALSE so that a newline
  1870.     **  immediately following the PRE start tag will
  1871.     **  be ignored.  HTML_put_character() will set it
  1872.     **  to TRUE when the first character within the
  1873.     **  PRE block is received. - FM
  1874.     */
  1875.     me->inPRE = FALSE;
  1876.     case HTML_LISTING:                /* Literal text */
  1877.     case HTML_XMP:
  1878.     case HTML_PLAINTEXT:
  1879.     change_paragraph_style(me, styles[ElementNumber]);
  1880.     UPDATE_STYLE;
  1881.     CHECK_ID(HTML_GEN_ID);
  1882.     if (me->comment_end)
  1883.         HText_appendText(me->text, me->comment_end);
  1884.     break;
  1885.  
  1886.     case HTML_BLOCKQUOTE:
  1887.     case HTML_BQ:
  1888.     change_paragraph_style(me, styles[ElementNumber]);
  1889.     UPDATE_STYLE;
  1890.     if (me->sp->tag_number == ElementNumber)
  1891.         LYEnsureDoubleSpace(me);
  1892.     CHECK_ID(HTML_BQ_ID);
  1893.     break;
  1894.  
  1895.     case HTML_NOTE:
  1896.     change_paragraph_style(me, styles[ElementNumber]);
  1897.     UPDATE_STYLE;
  1898.     if (me->sp->tag_number == ElementNumber)
  1899.         LYEnsureDoubleSpace(me);
  1900.     CHECK_ID(HTML_NOTE_ID);
  1901.     {
  1902.         char *note = NULL;
  1903.  
  1904.         /*
  1905.          *    Indicate the type of NOTE.
  1906.          */
  1907.         if (present && present[HTML_NOTE_CLASS] &&
  1908.         value[HTML_NOTE_CLASS] &&
  1909.         (!strcasecomp(value[HTML_NOTE_CLASS], "CAUTION") ||
  1910.          !strcasecomp(value[HTML_NOTE_CLASS], "WARNING"))) {
  1911.         StrAllocCopy(note, value[HTML_NOTE_CLASS]);
  1912.         LYUpperCase(note);
  1913.         StrAllocCat(note, ":");
  1914.         } else if (present && present[HTML_NOTE_ROLE] &&
  1915.                value[HTML_NOTE_ROLE] &&
  1916.                (!strcasecomp(value[HTML_NOTE_ROLE], "CAUTION") ||
  1917.             !strcasecomp(value[HTML_NOTE_ROLE], "WARNING"))) {
  1918.         StrAllocCopy(note, value[HTML_NOTE_ROLE]);
  1919.         LYUpperCase(note);
  1920.         StrAllocCat(note, ":");
  1921.         } else {
  1922.         StrAllocCopy(note, "NOTE:");
  1923.         }
  1924.         if (me->inUnderline == FALSE)
  1925.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  1926.         HTML_put_string(me, note);
  1927.         if (me->inUnderline == FALSE)
  1928.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  1929.         HTML_put_character(me, ' ');
  1930.         FREE(note);
  1931.     }
  1932.     me->inLABEL = TRUE;
  1933.     me->in_word = NO;
  1934.     me->inP = FALSE;
  1935.     break;
  1936.  
  1937.     case HTML_ADDRESS:
  1938.     change_paragraph_style(me, styles[ElementNumber]);
  1939.     UPDATE_STYLE;
  1940.     if (me->sp->tag_number == ElementNumber)
  1941.         LYEnsureDoubleSpace(me);
  1942.     CHECK_ID(HTML_ADDRESS_ID);
  1943.     break;
  1944.  
  1945.     case HTML_DL:
  1946.     me->List_Nesting_Level++;  /* increment the List nesting level */
  1947.     if (me->List_Nesting_Level <= 0) {
  1948.         change_paragraph_style(me, present && present[HTML_DL_COMPACT]
  1949.                       ? styles[HTML_DLC] : styles[HTML_DL]);
  1950.  
  1951.     } else if (me->List_Nesting_Level >= 6) {
  1952.         change_paragraph_style(me, present && present[HTML_DL_COMPACT]
  1953.                       ? styles[HTML_DLC6] : styles[HTML_DL6]);
  1954.  
  1955.     } else {
  1956.         change_paragraph_style(me, present && present[HTML_DL_COMPACT]
  1957.          ? styles[(HTML_DLC1 - 1) + me->List_Nesting_Level]
  1958.          : styles[(HTML_DL1 - 1) + me->List_Nesting_Level]);
  1959.     }
  1960.     UPDATE_STYLE;      /* update to the new style */
  1961.     CHECK_ID(HTML_DL_ID);
  1962.     break;
  1963.  
  1964.     case HTML_DLC:
  1965.     me->List_Nesting_Level++;  /* increment the List nesting level */
  1966.     if (me->List_Nesting_Level <= 0) {
  1967.         change_paragraph_style(me, styles[HTML_DLC]);
  1968.  
  1969.     } else if (me->List_Nesting_Level >= 6) {
  1970.         change_paragraph_style(me, styles[HTML_DLC6]);
  1971.  
  1972.     } else {
  1973.         change_paragraph_style(me,
  1974.                 styles[(HTML_DLC1 - 1) + me->List_Nesting_Level]);
  1975.     }
  1976.     UPDATE_STYLE;      /* update to the new style */
  1977.     CHECK_ID(HTML_DL_ID);
  1978.     break;
  1979.  
  1980.     case HTML_DT:
  1981.     CHECK_ID(HTML_GEN_ID);
  1982.     if (!me->style_change) {
  1983.         HText_appendParagraph(me->text);
  1984.         me->in_word = NO;
  1985.         me->sp->style->alignment = HT_LEFT;
  1986.     }
  1987.     me->inP = FALSE;
  1988.     break;
  1989.  
  1990.     case HTML_DD:
  1991.     CHECK_ID(HTML_GEN_ID);
  1992.     HText_setLastChar(me->text, ' ');  /* absorb white space */
  1993.     if (!me->style_change)    {
  1994.         if (HText_LastLineSize(me->text, FALSE)) {
  1995.         HText_appendCharacter(me->text, '\r');
  1996.         }
  1997.     } else {
  1998.         UPDATE_STYLE;
  1999.         HText_appendCharacter(me->text, '\t');
  2000.     }
  2001.     me->sp->style->alignment = HT_LEFT;
  2002.     me->in_word = NO;
  2003.     me->inP = FALSE;
  2004.     break;
  2005.  
  2006.     case HTML_OL:
  2007.     /*
  2008.      * Set the default TYPE.
  2009.      */
  2010.      me->OL_Type[(me->List_Nesting_Level < 11 ?
  2011.              me->List_Nesting_Level+1 : 11)] = '1';
  2012.  
  2013.     /*
  2014.      *  Check whether we have a starting sequence number,
  2015.      *  or want to continue the numbering from a previous
  2016.      *  OL in this nest. - FM
  2017.      */
  2018.     if (present && (present[HTML_OL_SEQNUM] || present[HTML_OL_START])) {
  2019.         int seqnum;
  2020.  
  2021.         /*
  2022.          *    Give preference to the valid HTML 3.0 SEQNUM attribute name
  2023.          *    over the Netscape START attribute name (too bad the Netscape
  2024.          *    developers didn't read the HTML 3.0 specs before re-inventing
  2025.          *    the "wheel" as "we'll"). - FM
  2026.          */
  2027.         if (present[HTML_OL_SEQNUM] &&
  2028.         value[HTML_OL_SEQNUM] && *value[HTML_OL_SEQNUM]) {
  2029.         seqnum = atoi(value[HTML_OL_SEQNUM]);
  2030.         } else if (present[HTML_OL_START] &&
  2031.                value[HTML_OL_START] && *value[HTML_OL_START]) {
  2032.         seqnum = atoi(value[HTML_OL_START]);
  2033.         } else {
  2034.         seqnum = 1;
  2035.         }
  2036.  
  2037.         /*
  2038.          *    Don't allow negative numbers less than
  2039.          *    or equal to our flags, or numbers less
  2040.          *    than 1 if an Alphabetic or Roman TYPE. - FM
  2041.          */
  2042.         if (present[HTML_OL_TYPE] && value[HTML_OL_TYPE]) {
  2043.         if (*value[HTML_OL_TYPE] == 'A') {
  2044.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2045.                     me->List_Nesting_Level+1 : 11)] = 'A';
  2046.             if (seqnum < 1)
  2047.             seqnum = 1;
  2048.         } else if (*value[HTML_OL_TYPE] == 'a') {
  2049.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2050.                     me->List_Nesting_Level+1 : 11)] = 'a';
  2051.             if (seqnum < 1)
  2052.             seqnum = 1;
  2053.         } else if (*value[HTML_OL_TYPE] == 'I') {
  2054.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2055.                     me->List_Nesting_Level+1 : 11)] = 'I';
  2056.             if (seqnum < 1)
  2057.             seqnum = 1;
  2058.         } else if (*value[HTML_OL_TYPE] == 'i') {
  2059.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2060.                     me->List_Nesting_Level+1 : 11)] = 'i';
  2061.             if (seqnum < 1)
  2062.             seqnum = 1;
  2063.         } else {
  2064.           if (seqnum <= OL_VOID)
  2065.               seqnum = OL_VOID + 1;
  2066.         }
  2067.         } else if (seqnum <= OL_VOID) {
  2068.         seqnum = OL_VOID + 1;
  2069.         }
  2070.  
  2071.         me->OL_Counter[(me->List_Nesting_Level < 11 ?
  2072.                    me->List_Nesting_Level+1 : 11)] = seqnum;
  2073.  
  2074.     } else if (present && present[HTML_OL_CONTINUE]) {
  2075.         me->OL_Counter[me->List_Nesting_Level < 11 ?
  2076.                   me->List_Nesting_Level+1 : 11] = OL_CONTINUE;
  2077.  
  2078.     } else {
  2079.         me->OL_Counter[(me->List_Nesting_Level < 11 ?
  2080.                    me->List_Nesting_Level+1 : 11)] = 1;
  2081.         if (present && present[HTML_OL_TYPE] && value[HTML_OL_TYPE]) {
  2082.         if (*value[HTML_OL_TYPE] == 'A') {
  2083.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2084.                     me->List_Nesting_Level+1 : 11)] = 'A';
  2085.         } else if (*value[HTML_OL_TYPE] == 'a') {
  2086.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2087.                     me->List_Nesting_Level+1 : 11)] = 'a';
  2088.         } else if (*value[HTML_OL_TYPE] == 'I') {
  2089.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2090.                     me->List_Nesting_Level+1 : 11)] = 'I';
  2091.         } else if (*value[HTML_OL_TYPE] == 'i') {
  2092.             me->OL_Type[(me->List_Nesting_Level < 11 ?
  2093.                     me->List_Nesting_Level+1 : 11)] = 'i';
  2094.         }
  2095.         }
  2096.     }
  2097.     me->List_Nesting_Level++;
  2098.  
  2099.     if (me->List_Nesting_Level <= 0) {
  2100.         change_paragraph_style(me, styles[ElementNumber]);
  2101.  
  2102.     } else if (me->List_Nesting_Level >= 6) {
  2103.         change_paragraph_style(me, styles[HTML_OL6]);
  2104.  
  2105.     } else {
  2106.         change_paragraph_style(me,
  2107.               styles[HTML_OL1 + me->List_Nesting_Level - 1]);
  2108.     }
  2109.     UPDATE_STYLE;  /* update to the new style */
  2110.     CHECK_ID(HTML_OL_ID);
  2111.     break;
  2112.  
  2113.     case HTML_UL:
  2114.     me->List_Nesting_Level++;
  2115.  
  2116.     if (me->List_Nesting_Level <= 0) {
  2117.         if (!(present && present[HTML_UL_PLAIN]) &&
  2118.         !(present && present[HTML_UL_TYPE] &&
  2119.           value[HTML_UL_TYPE] &&
  2120.           0==strcasecomp(value[HTML_UL_TYPE], "PLAIN"))) {
  2121.         change_paragraph_style(me, styles[ElementNumber]);
  2122.         } else {
  2123.         change_paragraph_style(me, styles[HTML_DIR]);
  2124.         ElementNumber = HTML_DIR;
  2125.         }
  2126.  
  2127.     } else if (me->List_Nesting_Level >= 6) {
  2128.         if (!(present && present[HTML_UL_PLAIN]) &&
  2129.         !(present && present[HTML_UL_TYPE] &&
  2130.           value[HTML_UL_TYPE] &&
  2131.           0==strcasecomp(value[HTML_UL_TYPE], "PLAIN"))) {
  2132.         change_paragraph_style(me, styles[HTML_OL6]);
  2133.         } else {
  2134.         change_paragraph_style(me, styles[HTML_MENU6]);
  2135.         ElementNumber = HTML_DIR;
  2136.         }
  2137.  
  2138.     } else {
  2139.         if (!(present && present[HTML_UL_PLAIN]) &&
  2140.         !(present && present[HTML_UL_TYPE] &&
  2141.           value[HTML_UL_TYPE] &&
  2142.           0==strcasecomp(value[HTML_UL_TYPE], "PLAIN"))) {
  2143.         change_paragraph_style(me,
  2144.               styles[HTML_OL1 + me->List_Nesting_Level - 1]);
  2145.         } else {
  2146.         change_paragraph_style(me,
  2147.               styles[HTML_MENU1 + me->List_Nesting_Level - 1]);
  2148.         ElementNumber = HTML_DIR;
  2149.         }
  2150.     }
  2151.     UPDATE_STYLE;  /* update to the new style */
  2152.     CHECK_ID(HTML_UL_ID);
  2153.     break;
  2154.  
  2155.     case HTML_MENU:
  2156.     case HTML_DIR:
  2157.     me->List_Nesting_Level++;
  2158.  
  2159.     if (me->List_Nesting_Level <= 0) {
  2160.         change_paragraph_style(me, styles[ElementNumber]);
  2161.  
  2162.     } else if (me->List_Nesting_Level >= 6) {
  2163.         change_paragraph_style(me, styles[HTML_MENU6]);
  2164.  
  2165.     } else {
  2166.         change_paragraph_style(me,
  2167.               styles[HTML_MENU1 + me->List_Nesting_Level - 1]);
  2168.     }
  2169.     UPDATE_STYLE;  /* update to the new style */
  2170.     CHECK_ID(HTML_UL_ID);
  2171.     break;
  2172.  
  2173.     case HTML_LH:
  2174.     UPDATE_STYLE;  /* update to the new style */
  2175.     HText_appendParagraph(me->text);
  2176.     CHECK_ID(HTML_GEN_ID);
  2177.     HTML_put_character(me, HT_NON_BREAK_SPACE);
  2178.     HText_setLastChar(me->text, ' ');
  2179.     me->in_word = NO;
  2180.     me->inP = FALSE;
  2181.     break;
  2182.  
  2183.     case HTML_LI:
  2184.     UPDATE_STYLE;  /* update to the new style */
  2185.     HText_appendParagraph(me->text);
  2186.     me->sp->style->alignment = HT_LEFT;
  2187.     CHECK_ID(HTML_LI_ID);
  2188.     if (me->sp[0].tag_number == HTML_OL) {
  2189.         char number_string[20];
  2190.         int counter, seqnum;
  2191.         char seqtype;
  2192.  
  2193.         counter = me->List_Nesting_Level < 11 ?
  2194.                me->List_Nesting_Level : 11;
  2195.         if (present && present[HTML_LI_TYPE] && value[HTML_LI_TYPE]) {
  2196.         if (*value[HTML_LI_TYPE] == '1') {
  2197.             me->OL_Type[counter] = '1';
  2198.         } else if (*value[HTML_LI_TYPE] == 'A') {
  2199.             me->OL_Type[counter] = 'A';
  2200.         } else if (*value[HTML_LI_TYPE] == 'a') {
  2201.             me->OL_Type[counter] = 'a';
  2202.         } else if (*value[HTML_LI_TYPE] == 'I') {
  2203.             me->OL_Type[counter] = 'I';
  2204.         } else if (*value[HTML_LI_TYPE] == 'i') {
  2205.             me->OL_Type[counter] = 'i';
  2206.         }
  2207.         }
  2208.         if (present && present[HTML_LI_VALUE] &&
  2209.         ((value[HTML_LI_VALUE] != NULL) &&
  2210.          (*value[HTML_LI_VALUE] != '\0')) &&
  2211.         ((isdigit(*value[HTML_LI_VALUE])) ||
  2212.          (*value[HTML_LI_VALUE] == '-' &&
  2213.           isdigit(*(value[HTML_LI_VALUE] + 1))))) {
  2214.         seqnum = atoi(value[HTML_LI_VALUE]);
  2215.         if (seqnum <= OL_VOID)
  2216.             seqnum = OL_VOID + 1;
  2217.         seqtype = me->OL_Type[counter];
  2218.         if (seqtype != '1' && seqnum < 1)
  2219.             seqnum = 1;
  2220.         me->OL_Counter[counter] = seqnum + 1;
  2221.         } else if (me->OL_Counter[counter] >= OL_VOID) {
  2222.         seqnum = me->OL_Counter[counter]++;
  2223.         seqtype = me->OL_Type[counter];
  2224.         if (seqtype != '1' && seqnum < 1) {
  2225.             seqnum = 1;
  2226.             me->OL_Counter[counter] = seqnum + 1;
  2227.         }
  2228.         } else {
  2229.         seqnum = me->Last_OL_Count + 1;
  2230.         seqtype = me->Last_OL_Type;
  2231.         for (i = (counter - 1); i >= 0; i--) {
  2232.             if (me->OL_Counter[i] > OL_VOID) {
  2233.             seqnum = me->OL_Counter[i]++;
  2234.             seqtype = me->OL_Type[i];
  2235.             i = 0;
  2236.             }
  2237.         }
  2238.         }
  2239.         if (seqtype == 'A') {
  2240.         sprintf(number_string, LYUppercaseA_OL_String(seqnum));
  2241.         } else if (seqtype == 'a') {
  2242.         sprintf(number_string, LYLowercaseA_OL_String(seqnum));
  2243.         } else if (seqtype == 'I') {
  2244.         sprintf(number_string, LYUppercaseI_OL_String(seqnum));
  2245.         } else if (seqtype == 'i') {
  2246.         sprintf(number_string, LYLowercaseI_OL_String(seqnum));
  2247.         } else {
  2248.         sprintf(number_string, "%2d.", seqnum);
  2249.         }
  2250.         me->Last_OL_Count = seqnum;
  2251.         me->Last_OL_Type = seqtype;
  2252.         /*
  2253.          *    Hack, because there is no append string!
  2254.          */
  2255.         for (i = 0; number_string[i] != '\0'; i++)
  2256.         if (number_string[i] == ' ')
  2257.             HTML_put_character(me, HT_NON_BREAK_SPACE);
  2258.         else
  2259.             HTML_put_character(me, number_string[i]);
  2260.  
  2261.         /*
  2262.          *    Use HTML_put_character so that any other spaces
  2263.          *    coming through will be collapsed.  We'll use
  2264.          *    nbsp, so it won't break at the spacing character
  2265.          *    if there are no spaces in the subsequent text up
  2266.          *    to the right margin, but will declare it as a
  2267.          *    normal space to ensure collapsing if a normal
  2268.          *    space does immediately follow it. - FM
  2269.          */
  2270.         HTML_put_character(me, HT_NON_BREAK_SPACE);
  2271.         HText_setLastChar(me->text, ' ');
  2272.     } else if (me->sp[0].tag_number == HTML_UL) {
  2273.         /*
  2274.          *    Hack, because there is no append string!
  2275.          */
  2276.         HTML_put_character(me, HT_NON_BREAK_SPACE);
  2277.         HTML_put_character(me, HT_NON_BREAK_SPACE);
  2278.         switch(me->List_Nesting_Level % 7) {
  2279.         case 0:
  2280.             HTML_put_character(me, '*');
  2281.             break;
  2282.         case 1:
  2283.             HTML_put_character(me, '+');
  2284.             break;
  2285.         case 2:
  2286.             HTML_put_character(me, 'o');
  2287.             break;
  2288.         case 3:
  2289.             HTML_put_character(me, '#');
  2290.             break;
  2291.         case 4:
  2292.             HTML_put_character(me, '@');
  2293.             break;
  2294.         case 5:
  2295.             HTML_put_character(me, '-');
  2296.             break;
  2297.         case 6:
  2298.             HTML_put_character(me, '=');
  2299.             break;
  2300.  
  2301.         }
  2302.         /*
  2303.          *    Keep using HTML_put_character so that any other
  2304.          *    spaces coming through will be collapsed.  We use
  2305.          *    nbsp, so we won't wrap at the spacing character
  2306.          *    if there are no spaces in the subsequent text up
  2307.          *    to the right margin, but will declare it as a
  2308.          *    normal space to ensure collapsing if a normal
  2309.          *    space does immediately follow it. - FM
  2310.          */
  2311.         HTML_put_character(me, HT_NON_BREAK_SPACE);
  2312.         HText_setLastChar(me->text, ' ');
  2313.     } else {
  2314.         /*
  2315.          *    Hack, because there is no append string!
  2316.          */
  2317.         HTML_put_character(me, HT_NON_BREAK_SPACE);
  2318.         HTML_put_character(me, HT_NON_BREAK_SPACE);
  2319.         HText_setLastChar(me->text, ' ');
  2320.     }
  2321.     me->in_word = NO;
  2322.     me->inP = FALSE;
  2323.     break;
  2324.  
  2325.     case HTML_SPAN:
  2326.     CHECK_ID(HTML_GEN_ID);
  2327.     /*
  2328.      *  Should check LANG and/or DIR attributes, and the
  2329.      *  me->node_anchor->charset and/or yet to be added
  2330.      *  structure elements, and do something here. - FM
  2331.      */
  2332.     break;
  2333.  
  2334.     case HTML_BDO:
  2335.     CHECK_ID(HTML_GEN_ID);
  2336.     /*
  2337.      *  Should check DIR (and LANG) attributes, and the
  2338.      *  me->node_anchor->charset and/or yet to be added
  2339.      *  structure elements, and do something here. - FM
  2340.      */
  2341.     break;
  2342.  
  2343.     case HTML_SPOT:
  2344.     CHECK_ID(HTML_GEN_ID);
  2345.     break;
  2346.  
  2347.     case HTML_FN:
  2348.     change_paragraph_style(me, styles[ElementNumber]);
  2349.     UPDATE_STYLE;
  2350.     if (me->sp->tag_number == ElementNumber)
  2351.         LYEnsureDoubleSpace(me);
  2352.     CHECK_ID(HTML_FN_ID);
  2353.     if (me->inUnderline == FALSE)
  2354.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  2355.     HTML_put_string(me, "FOOTNOTE:");
  2356.     if (me->inUnderline == FALSE)
  2357.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  2358.     HTML_put_character(me, ' ');
  2359.     me->inLABEL = TRUE;
  2360.     me->in_word = NO;
  2361.     me->inP = FALSE;
  2362.     break;
  2363.  
  2364.     case HTML_A:
  2365.     /*
  2366.      *  A may have been declared SGML_EMPTY in HTMLDTD.c, and
  2367.      *  SGML_character() in SGML.c may check for an A end
  2368.      *  tag to call HTML_end_element() directly (with a
  2369.      *  check in that to bypass decrementing of the HTML
  2370.      *  parser's stack), so if we have an open A, close
  2371.      *  that one now. - FM & kw
  2372.      */
  2373.     if (me->inA) {
  2374.         SET_SKIP_STACK(HTML_A);
  2375.         HTML_end_element(me, HTML_A, (char **)&include);
  2376.     }
  2377.     /*
  2378.      *  Set to know we are in an anchor.
  2379.      */
  2380.     me->inA = TRUE;
  2381.  
  2382.     /*
  2383.      *  Load id_string if we have an ID or NAME. - FM
  2384.      */
  2385.     if (present && present[HTML_A_ID] &&
  2386.         value[HTML_A_ID] && *value[HTML_A_ID]) {
  2387.         StrAllocCopy(id_string, value[HTML_A_ID]);
  2388.     } else if (present && present[HTML_A_NAME] &&
  2389.            value[HTML_A_NAME] && *value[HTML_A_NAME]) {
  2390.         StrAllocCopy(id_string, value[HTML_A_NAME]);
  2391.     }
  2392.     if (id_string) {
  2393.         TRANSLATE_AND_UNESCAPE_TO_STD(&id_string);
  2394.         if (*id_string == '\0') {
  2395.         FREE(id_string);
  2396.         }
  2397.     }
  2398.  
  2399.     /*
  2400.      *  Handle the reference. - FM
  2401.      */
  2402.     if (present && present[HTML_A_HREF]) {
  2403. #ifndef DONT_TRACK_INTERNAL_LINKS
  2404.         if (present[HTML_A_ISMAP])
  2405.         intern_flag = FALSE;
  2406.         else
  2407.         CHECK_FOR_INTERN(value[HTML_A_HREF]);
  2408. #endif
  2409.         /*
  2410.          *    Prepare to do housekeeping on the reference. - FM
  2411.          */
  2412.         if (!value[HTML_A_HREF] || *value[HTML_A_HREF] == '\0') {
  2413.         StrAllocCopy(href, me->node_anchor->address);
  2414.         } else if (*value[HTML_A_HREF] == '#') {
  2415.         StrAllocCopy(href, me->node_anchor->address);
  2416.         if (strlen(value[HTML_A_HREF]) > 1) {
  2417.             StrAllocCat(href, value[HTML_A_HREF]);
  2418.         }
  2419.         } else {
  2420.         StrAllocCopy(href, value[HTML_A_HREF]);
  2421.         }
  2422.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  2423.  
  2424.         /*
  2425.          *    Deal with our ftp gateway kludge. - FM
  2426.          */
  2427.         if (!url_type && !strncmp(href, "/foo/..", 7) &&
  2428.         (!strncmp(me->node_anchor->address, "ftp:", 4) ||
  2429.          !strncmp(me->node_anchor->address, "file:", 5))) {
  2430.         for (i = 0; href[i]; i++)
  2431.             href[i] = href[i+7];
  2432.         }
  2433.  
  2434.         /*
  2435.          *    Set to know we are making the content bold.
  2436.          */
  2437.         me->inBoldA = TRUE;
  2438.  
  2439.         /*
  2440.          *    Check whether a base tag is in effect. - FM
  2441.          */
  2442.         if ((me->inBASE && *href != '\0' && *href != '#') &&
  2443.         (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  2444.         *temp != '\0')
  2445.         /*
  2446.          *  Use reference related to the base.
  2447.          */
  2448.         StrAllocCopy(href, temp);
  2449.         FREE(temp);
  2450.  
  2451.         /*
  2452.          *    Check whether to fill in localhost. - FM
  2453.          */
  2454.         LYFillLocalFileURL((char **)&href,
  2455.                    ((*href != '\0' && *href != '#' &&
  2456.                  me->inBASE) ?
  2457.                    me->base_href : me->node_anchor->address));
  2458.     } else {
  2459.         if (bold_name_anchors == TRUE) {
  2460.         me->inBoldA = TRUE;
  2461.         }
  2462.     }
  2463. #ifndef DONT_TRACK_INTERNAL_LINKS
  2464.     if (present && present[HTML_A_TYPE] && value[HTML_A_TYPE]) {
  2465.         StrAllocCopy(temp, value[HTML_A_TYPE]);
  2466.         if (!intern_flag && href &&
  2467.         !strcasecomp(value[HTML_A_TYPE], HTAtom_name(LINK_INTERNAL)) &&
  2468.         0 != strcmp(me->node_anchor->address, LYlist_temp_url()) &&
  2469.         0 != strncmp(me->node_anchor->address, "LYNXIMGMAP:", 11)) {
  2470.         /* Some kind of spoof?
  2471.         ** Found TYPE="internal link" but not in a valid context
  2472.         ** where we have written it. - kw
  2473.         */
  2474.         CTRACE(tfp, "HTML: Found invalid HREF=\"%s\" TYPE=\"%s\"!\n",
  2475.                 href, temp);
  2476.         FREE(temp);
  2477.         }
  2478.     }
  2479. #endif /* DONT_TRACK_INTERNAL_LINKS */
  2480.  
  2481.     me->CurrentA = HTAnchor_findChildAndLink(
  2482.             me->node_anchor,            /* Parent */
  2483.             id_string,                /* Tag */
  2484.             href,                    /* Address */
  2485.             temp ?
  2486.         (HTLinkType*)HTAtom_for(temp) : INTERN_LT);  /* Type */
  2487.     FREE(temp);
  2488.     FREE(id_string);
  2489.  
  2490.     if (me->CurrentA && present) {
  2491.         if (present[HTML_A_TITLE] &&
  2492.         value[HTML_A_TITLE] && *value[HTML_A_TITLE] != '\0') {
  2493.         StrAllocCopy(title, value[HTML_A_TITLE]);
  2494.         TRANSLATE_AND_UNESCAPE_ENTITIES(&title, TRUE, FALSE);
  2495.         LYTrimHead(title);
  2496.         LYTrimTail(title);
  2497.         if (*title == '\0') {
  2498.             FREE(title);
  2499.         }
  2500.         }
  2501.         if (present[HTML_A_ISMAP])
  2502.         dest_ismap = TRUE;
  2503.         if (present[HTML_A_CHARSET] &&
  2504.         value[HTML_A_CHARSET] && *value[HTML_A_CHARSET] != '\0') {
  2505.         /*
  2506.         **  Set up to load the anchor's chartrans structures
  2507.         **  appropriately for the current display character
  2508.         **  set if it can handle what's claimed. - FM
  2509.         */
  2510.         StrAllocCopy(temp, value[HTML_A_CHARSET]);
  2511.         TRANSLATE_AND_UNESCAPE_TO_STD(&temp);
  2512.         dest_char_set = UCGetLYhndl_byMIME(temp);
  2513.         if (dest_char_set < 0) {
  2514.             dest_char_set = UCLYhndl_for_unrec;
  2515.         }
  2516.         }
  2517.         if (title != NULL || dest_ismap == TRUE || dest_char_set >= 0) {
  2518.         dest = HTAnchor_parent(
  2519.             HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
  2520.                       );
  2521.         }
  2522.         if (dest && title != NULL && HTAnchor_title(dest) == NULL)
  2523.         HTAnchor_setTitle(dest, title);
  2524.         if (dest && dest_ismap)
  2525.         dest->isISMAPScript = TRUE;
  2526.         if (dest && dest_char_set >= 0) {
  2527.         /*
  2528.         **  Load the anchor's chartrans structures.
  2529.         **  This should be done more intelligently
  2530.         **  when setting up the structured object,
  2531.         **  but it gets the job done for now. - FM
  2532.         */
  2533.         HTAnchor_setUCInfoStage(dest, dest_char_set,
  2534.                     UCT_STAGE_MIME,
  2535.                     UCT_SETBY_DEFAULT);
  2536.         HTAnchor_setUCInfoStage(dest, dest_char_set,
  2537.                     UCT_STAGE_PARSER,
  2538.                     UCT_SETBY_LINK);
  2539.         }
  2540.         FREE(temp);
  2541.         dest = NULL;
  2542.         dest_ismap = FALSE;
  2543.         dest_char_set = -1;
  2544.         FREE(title);
  2545.     }
  2546.     me->CurrentANum = HText_beginAnchor(me->text,
  2547.                         me->inUnderline, me->CurrentA);
  2548.     if (me->inBoldA == TRUE && me->inBoldH == FALSE)
  2549.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  2550. #ifdef NOTUSED_FOTEMODS
  2551.     /*
  2552.      *  Close an HREF-less NAMED-ed now if we aren't making their
  2553.      *  content bold, and let the check in HTML_end_element() deal
  2554.      *  with any dangling end tag this creates. - FM
  2555.      */
  2556.     if (href == NULL && me->inBoldA == FALSE) {
  2557.         SET_SKIP_STACK(HTML_A);
  2558.         HTML_end_element(me, HTML_A, (char **)&include);
  2559.     }
  2560. #endif /* NOTUSED_FOTEMODS */
  2561.     FREE(href);
  2562.     break;
  2563.  
  2564.     case HTML_IMG:            /* Images */
  2565.     /*
  2566.      *  If we're in an anchor, get the destination, and if it's a
  2567.      *  clickable image for the current anchor, set our flags for
  2568.      *  faking a 0,0 coordinate pair, which typically returns the
  2569.      *  image's default. - FM
  2570.      */
  2571.     if (me->inA && me->CurrentA) {
  2572.         if ((dest = HTAnchor_parent(
  2573.             HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
  2574.                       )) != NULL) {
  2575.         if (dest->isISMAPScript == TRUE) {
  2576.             dest_ismap = TRUE;
  2577.             CTRACE(tfp, "HTML: '%s' is an ISMAP script\n",
  2578.                 dest->address);
  2579.         } else if (present && present[HTML_IMG_ISMAP]) {
  2580.             dest_ismap = TRUE;
  2581.             dest->isISMAPScript = TRUE;
  2582.             CTRACE(tfp, "HTML: Designating '%s' as an ISMAP script\n",
  2583.                 dest->address);
  2584.         }
  2585.         }
  2586.     }
  2587.  
  2588. #ifndef DONT_TRACK_INTERNAL_LINKS
  2589.     intern_flag = FALSE;    /* unless set below - kw */
  2590. #endif
  2591.     /*
  2592.      *  If there's a USEMAP, resolve it. - FM
  2593.      */
  2594.     if (present && present[HTML_IMG_USEMAP] &&
  2595.         value[HTML_IMG_USEMAP] && *value[HTML_IMG_USEMAP]) {
  2596.         StrAllocCopy(map_href, value[HTML_IMG_USEMAP]);
  2597.         CHECK_FOR_INTERN(map_href);
  2598.         url_type = LYLegitimizeHREF(me, (char**)&map_href, TRUE, TRUE);
  2599.         /*
  2600.          *    If map_href ended up zero-length or otherwise doesn't
  2601.          *    have a hash, it can't be valid, so ignore it. - FM
  2602.          */
  2603.         if (strchr(map_href, '#') == NULL) {
  2604.         FREE(map_href);
  2605.         }
  2606.     }
  2607.  
  2608.     /*
  2609.      *  Handle a MAP reference if we have one at this point. - FM
  2610.      */
  2611.     if (map_href) {
  2612.         /*
  2613.          *    If the MAP reference doesn't yet begin with a scheme,
  2614.          *    check whether a base tag is in effect. - FM
  2615.          */
  2616.         if (!url_type && me->inBASE) {
  2617.         /*
  2618.          *  If the
  2619.          *  USEMAP value is a lone fragment and LYSeekFragMAPinCur
  2620.          *  is set, we'll use the current document's URL for
  2621.          *  resolving.    Otherwise use the BASE. - kw
  2622.          */
  2623.         if ((*map_href == '#' &&
  2624.              LYSeekFragMAPinCur == TRUE)) {
  2625.             /*
  2626.              *    Use reference related to the current stream. - FM
  2627.              */
  2628.             temp = HTParse(map_href, me->node_anchor->address,
  2629.                     PARSE_ALL);
  2630.             StrAllocCopy(map_href, temp);
  2631.             UseBASE = FALSE;
  2632.         } else {
  2633.             /*
  2634.              *    Use reference related to the base. - FM
  2635.              */
  2636.             temp = HTParse(map_href, me->base_href, PARSE_ALL);
  2637.             StrAllocCopy(map_href, temp);
  2638.             UseBASE = TRUE;
  2639.         }
  2640.         FREE(temp);
  2641.         }
  2642.  
  2643.         /*
  2644.          *    Check whether to fill in localhost. - FM
  2645.          */
  2646.         LYFillLocalFileURL((char **)&map_href,
  2647.                    ((UseBASE && me->inBASE) ?
  2648.               me->base_href : me->node_anchor->address));
  2649.         UseBASE = TRUE;
  2650.  
  2651.         /*
  2652.          *    If it's not yet a URL, resolve versus
  2653.          *    the current document's address. - FM
  2654.          */
  2655.         if (!(url_type = is_url(map_href))) {
  2656.         temp = HTParse(map_href, me->node_anchor->address, PARSE_ALL);
  2657.         StrAllocCopy(map_href, temp);
  2658.         FREE(temp);
  2659.         }
  2660.  
  2661.         /*
  2662.          *    Prepend our client-side MAP access field. - FM
  2663.          */
  2664.         StrAllocCopy(temp, "LYNXIMGMAP:");
  2665.         StrAllocCat(temp, map_href);
  2666.         StrAllocCopy(map_href, temp);
  2667.         FREE(temp);
  2668.     }
  2669.  
  2670.     /*
  2671.      *  Check whether we want to suppress the server-side
  2672.      *  ISMAP link if a client-side MAP is present. - FM
  2673.      */
  2674.     if (LYNoISMAPifUSEMAP && map_href && dest_ismap) {
  2675.         dest_ismap = FALSE;
  2676.         dest = NULL;
  2677.     }
  2678.  
  2679.     /*
  2680.      *  Check for a TITLE attribute. - FM
  2681.      */
  2682.     if (present && present[HTML_IMG_TITLE] &&
  2683.         value[HTML_IMG_TITLE] && *value[HTML_IMG_TITLE]) {
  2684.         StrAllocCopy(title, value[HTML_IMG_TITLE]);
  2685.         TRANSLATE_AND_UNESCAPE_ENTITIES(&title, TRUE, FALSE);
  2686.         LYTrimHead(title);
  2687.         LYTrimTail(title);
  2688.         if (*title == '\0') {
  2689.         FREE(title);
  2690.         }
  2691.     }
  2692.  
  2693.     /*
  2694.      *  If there's an ALT string, use it, unless the ALT string
  2695.      *  is zero-length or just spaces and we are making all SRCs
  2696.      *  links or have a USEMAP link. - FM
  2697.      */
  2698.     if (((present) &&
  2699.          (present[HTML_IMG_ALT] && value[HTML_IMG_ALT])) &&
  2700.         (!clickable_images ||
  2701.          ((clickable_images || map_href) &&
  2702.           *value[HTML_IMG_ALT] != '\0'))) {
  2703.         StrAllocCopy(alt_string, value[HTML_IMG_ALT]);
  2704.         TRANSLATE_AND_UNESCAPE_ENTITIES(&alt_string,
  2705.                         me->UsePlainSpace, me->HiddenValue);
  2706.         /*
  2707.          *    If it's all spaces and we are making SRC or
  2708.          *    USEMAP links, treat it as zero-length. - FM
  2709.          */
  2710.         if (clickable_images || map_href) {
  2711.         LYTrimHead(alt_string);
  2712.         LYTrimTail(alt_string);
  2713.         if (*alt_string == '\0') {
  2714.             if (map_href) {
  2715.             StrAllocCopy(alt_string, (title ?
  2716.                           title : "[USEMAP]"));
  2717.             } else if (dest_ismap) {
  2718.             StrAllocCopy(alt_string, (title ?
  2719.                           title : "[ISMAP]"));
  2720.  
  2721.             } else if (me->inA == TRUE && dest) {
  2722.             StrAllocCopy(alt_string, (title ?
  2723.                           title :
  2724.                           VERBOSE_IMG(value, "[LINK]")));
  2725.  
  2726.             } else {
  2727.             StrAllocCopy(alt_string,
  2728.                          (title ? title :
  2729.                           ((present &&
  2730.                             present[HTML_IMG_ISOBJECT]) ?
  2731.                             "(OBJECT)" :
  2732.                             VERBOSE_IMG(value, "[INLINE]"))));
  2733.             }
  2734.         }
  2735.         }
  2736.  
  2737.     } else if (map_href) {
  2738.         StrAllocCopy(alt_string, (title ?
  2739.                       title : "[USEMAP]"));
  2740.  
  2741.     } else if ((dest_ismap == TRUE) ||
  2742.            (me->inA && present && present[HTML_IMG_ISMAP])) {
  2743.         StrAllocCopy(alt_string, (title ?
  2744.                       title : "[ISMAP]"));
  2745.  
  2746.     } else if (me->inA == TRUE && dest) {
  2747.         StrAllocCopy(alt_string, (title ?
  2748.                       title :
  2749.                       VERBOSE_IMG(value, "[LINK]")));
  2750.  
  2751.     } else {
  2752.         if (pseudo_inline_alts || clickable_images)
  2753.         StrAllocCopy(alt_string, (title ? title :
  2754.               ((present &&
  2755.                 present[HTML_IMG_ISOBJECT]) ?
  2756.                          "(OBJECT)" :
  2757.                          VERBOSE_IMG(value, "[INLINE]"))));
  2758.         else
  2759.         StrAllocCopy(alt_string, (title ?
  2760.                       title : ""));
  2761.     }
  2762.     if (*alt_string == '\0' && map_href) {
  2763.         StrAllocCopy(alt_string, "[USEMAP]");
  2764.     }
  2765.  
  2766.     CTRACE(tfp, "HTML IMG: USEMAP=%d ISMAP=%d ANCHOR=%d PARA=%d\n",
  2767.             map_href ? 1 : 0,
  2768.             (dest_ismap == TRUE) ? 1 : 0,
  2769.             me->inA, me->inP);
  2770.  
  2771.     /*
  2772.      *  Check for an ID attribute. - FM
  2773.      */
  2774.     if (present && present[HTML_IMG_ID] &&
  2775.         value[HTML_IMG_ID] && *value[HTML_IMG_ID]) {
  2776.         StrAllocCopy(id_string, value[HTML_IMG_ID]);
  2777.         TRANSLATE_AND_UNESCAPE_TO_STD(&id_string);
  2778.         if (*id_string == '\0') {
  2779.         FREE(id_string);
  2780.         }
  2781.     }
  2782.  
  2783.     /*
  2784.      *  Create links to the SRC for all images, if desired. - FM
  2785.      */
  2786.     if (clickable_images &&
  2787.         present && present[HTML_IMG_SRC] &&
  2788.         value[HTML_IMG_SRC] && *value[HTML_IMG_SRC] != '\0') {
  2789.         StrAllocCopy(href, value[HTML_IMG_SRC]);
  2790.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  2791.  
  2792.         /*
  2793.          *    Check whether a base tag is in effect. - FM
  2794.          */
  2795.         if ((me->inBASE && *href != '\0' && *href != '#') &&
  2796.         (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  2797.         *temp != '\0')
  2798.         /*
  2799.          *  Use reference related to the base.
  2800.          */
  2801.         StrAllocCopy(href, temp);
  2802.         FREE(temp);
  2803.  
  2804.         /*
  2805.          *    Check whether to fill in localhost. - FM
  2806.          */
  2807.         LYFillLocalFileURL((char **)&href,
  2808.                    ((*href != '\0' && *href != '#' &&
  2809.                  me->inBASE) ?
  2810.                    me->base_href : me->node_anchor->address));
  2811.  
  2812.         /*
  2813.          *    If it's an ISMAP and/or USEMAP, or graphic for an
  2814.          *    anchor, end that anchor and start one for the SRC. - FM
  2815.          */
  2816.         if (me->inA) {
  2817.         /*
  2818.          *  If we have a USEMAP, end this anchor and
  2819.          *  start a new one for the client-side MAP. - FM
  2820.          */
  2821.         if (map_href) {
  2822.             if (dest_ismap) {
  2823.             HTML_put_character(me, ' ');
  2824.             me->in_word = NO;
  2825.             HTML_put_string(me, "[ISMAP]");
  2826.             } else if (dest) {
  2827.             HTML_put_character(me, ' ');
  2828.             me->in_word = NO;
  2829.             HTML_put_string(me, "[LINK]");
  2830.             }
  2831.             if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
  2832.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  2833.             }
  2834.             me->inBoldA = FALSE;
  2835.             HText_endAnchor(me->text, me->CurrentANum);
  2836.             me->CurrentANum = 0;
  2837.             if (dest_ismap || dest)
  2838.             HTML_put_character(me, '-');
  2839.             if (id_string) {
  2840.             if ((ID_A = HTAnchor_findChildAndLink(
  2841.                   me->node_anchor,    /* Parent */
  2842.                   id_string,        /* Tag */
  2843.                   NULL,         /* Addresss */
  2844.                   (HTLinkType*)0)) != NULL) {    /* Type */
  2845.                 HText_beginAnchor(me->text, me->inUnderline, ID_A);
  2846.                 HText_endAnchor(me->text, 0);
  2847.             }
  2848.             }
  2849.             me->CurrentA = HTAnchor_findChildAndLink(
  2850.                 me->node_anchor,    /* Parent */
  2851.                 NULL,            /* Tag */
  2852.                 map_href,        /* Addresss */
  2853.                 INTERN_LT);        /* Type */
  2854.             if (me->CurrentA && title) {
  2855.             if ((dest = HTAnchor_parent(
  2856.                 HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
  2857.                           )) != NULL) {
  2858.                 if (!HTAnchor_title(dest))
  2859.                 HTAnchor_setTitle(dest, title);
  2860.             }
  2861.             }
  2862.             me->CurrentANum = HText_beginAnchor(me->text,
  2863.                             me->inUnderline,
  2864.                             me->CurrentA);
  2865.             if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
  2866.             HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  2867.             }
  2868.             me->inBoldA = TRUE;
  2869.         } else {
  2870.             HTML_put_character(me, ' ');/* space char may be ignored */
  2871.             me->in_word = NO;
  2872.         }
  2873.         HTML_put_string(me, alt_string);
  2874.         if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
  2875.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  2876.         }
  2877.         me->inBoldA = FALSE;
  2878.         HText_endAnchor(me->text, me->CurrentANum);
  2879.         me->CurrentANum = 0;
  2880.         HTML_put_character(me, '-');
  2881.         StrAllocCopy(alt_string,
  2882.                  ((present &&
  2883.                    present[HTML_IMG_ISOBJECT]) ?
  2884.            ((map_href || dest_ismap) ?
  2885.                    "(IMAGE)" : "(OBJECT)") :
  2886.                    VERBOSE_IMG(value, "[IMAGE]")));
  2887.         if (id_string && !map_href) {
  2888.             if ((ID_A = HTAnchor_findChildAndLink(
  2889.                   me->node_anchor,    /* Parent */
  2890.                   id_string,        /* Tag */
  2891.                   NULL,         /* Addresss */
  2892.                   (HTLinkType*)0)) != NULL) {    /* Type */
  2893.             HText_beginAnchor(me->text, me->inUnderline, ID_A);
  2894.             HText_endAnchor(me->text, 0);
  2895.             }
  2896.         }
  2897.         } else if (map_href) {
  2898.         HTML_put_character(me, ' ');  /* space char may be ignored */
  2899.         me->in_word = NO;
  2900.         if (id_string) {
  2901.             if ((ID_A = HTAnchor_findChildAndLink(
  2902.                   me->node_anchor,    /* Parent */
  2903.                   id_string,        /* Tag */
  2904.                   NULL,         /* Addresss */
  2905.                   (HTLinkType*)0)) != NULL) {    /* Type */
  2906.             HText_beginAnchor(me->text, me->inUnderline, ID_A);
  2907.             HText_endAnchor(me->text, 0);
  2908.             }
  2909.         }
  2910.         me->CurrentA = HTAnchor_findChildAndLink(
  2911.                 me->node_anchor,    /* Parent */
  2912.                 NULL,            /* Tag */
  2913.                 map_href,        /* Addresss */
  2914.                 INTERN_LT);        /* Type */
  2915.         if (me->CurrentA && title) {
  2916.             if ((dest = HTAnchor_parent(
  2917.                 HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
  2918.                           )) != NULL) {
  2919.             if (!HTAnchor_title(dest))
  2920.                 HTAnchor_setTitle(dest, title);
  2921.             }
  2922.         }
  2923.         me->CurrentANum = HText_beginAnchor(me->text,
  2924.                             me->inUnderline,
  2925.                             me->CurrentA);
  2926.         if (me->inBoldA == FALSE && me->inBoldH == FALSE)
  2927.             HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  2928.         me->inBoldA = TRUE;
  2929.         HTML_put_string(me, alt_string);
  2930.         if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
  2931.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  2932.         }
  2933.         me->inBoldA = FALSE;
  2934.         HText_endAnchor(me->text, me->CurrentANum);
  2935.         me->CurrentANum = 0;
  2936.         HTML_put_character(me, '-');
  2937.         StrAllocCopy(alt_string,
  2938.                  ((present &&
  2939.                    present[HTML_IMG_ISOBJECT]) ?
  2940.                          "(IMAGE)" :
  2941.                          VERBOSE_IMG(value, "[IMAGE]")));
  2942.         } else {
  2943.         HTML_put_character(me, ' ');  /* space char may be ignored */
  2944.         me->in_word = NO;
  2945.         if (id_string) {
  2946.             if ((ID_A = HTAnchor_findChildAndLink(
  2947.                   me->node_anchor,    /* Parent */
  2948.                   id_string,        /* Tag */
  2949.                   NULL,         /* Addresss */
  2950.                   (HTLinkType*)0)) != NULL) {    /* Type */
  2951.             HText_beginAnchor(me->text, me->inUnderline, ID_A);
  2952.             HText_endAnchor(me->text, 0);
  2953.             }
  2954.         }
  2955.         }
  2956.  
  2957.         /*
  2958.          *    Create the link to the SRC. - FM
  2959.          */
  2960.         me->CurrentA = HTAnchor_findChildAndLink(
  2961.             me->node_anchor,        /* Parent */
  2962.             NULL,                /* Tag */
  2963.             href,                /* Addresss */
  2964.             (HTLinkType*)0);        /* Type */
  2965.         FREE(href);
  2966.         me->CurrentANum = HText_beginAnchor(me->text,
  2967.                         me->inUnderline,
  2968.                         me->CurrentA);
  2969.         if (me->inBoldH == FALSE)
  2970.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  2971.         HTML_put_string(me, alt_string);
  2972.         if (!me->inA) {
  2973.         if (me->inBoldH == FALSE)
  2974.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  2975.         HText_endAnchor(me->text, me->CurrentANum);
  2976.         me->CurrentANum = 0;
  2977.         HTML_put_character(me, ' ');  /* space char may be ignored */
  2978.         me->in_word = NO;
  2979.         } else {
  2980.         HTML_put_character(me, ' ');  /* space char may be ignored */
  2981.         me->in_word = NO;
  2982.         me->inBoldA = TRUE;
  2983.         }
  2984.     } else if (map_href) {
  2985.         if (me->inA) {
  2986.         /*
  2987.          *  We're in an anchor and have a USEMAP, so end the anchor
  2988.          *  and start a new one for the client-side MAP. - FM
  2989.          */
  2990.         if (dest_ismap) {
  2991.             HTML_put_character(me, ' ');/* space char may be ignored */
  2992.             me->in_word = NO;
  2993.             HTML_put_string(me, "[ISMAP]");
  2994.         } else if (dest) {
  2995.             HTML_put_character(me, ' ');/* space char may be ignored */
  2996.             me->in_word = NO;
  2997.             HTML_put_string(me, "[LINK]");
  2998.         }
  2999.         if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
  3000.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3001.         }
  3002.         me->inBoldA = FALSE;
  3003.         HText_endAnchor(me->text, me->CurrentANum);
  3004.         me->CurrentANum = 0;
  3005.         if (dest_ismap || dest) {
  3006.             HTML_put_character(me, '-');
  3007.         }
  3008.         } else {
  3009.         HTML_put_character(me, ' ');
  3010.         me->in_word = NO;
  3011.         }
  3012.         me->CurrentA = HTAnchor_findChildAndLink(
  3013.                 me->node_anchor,    /* Parent */
  3014.                 NULL,            /* Tag */
  3015.                 map_href,        /* Addresss */
  3016.                 INTERN_LT);        /* Type */
  3017.         if (me->CurrentA && title) {
  3018.         if ((dest = HTAnchor_parent(
  3019.                 HTAnchor_followMainLink((HTAnchor*)me->CurrentA)
  3020.                       )) != NULL) {
  3021.             if (!HTAnchor_title(dest))
  3022.             HTAnchor_setTitle(dest, title);
  3023.         }
  3024.         }
  3025.         me->CurrentANum = HText_beginAnchor(me->text,
  3026.                         me->inUnderline,
  3027.                         me->CurrentA);
  3028.         if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
  3029.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  3030.         }
  3031.         me->inBoldA = TRUE;
  3032.         HTML_put_string(me, alt_string);
  3033.         if (!me->inA) {
  3034.         if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
  3035.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3036.         }
  3037.         me->inBoldA = FALSE;
  3038.         HText_endAnchor(me->text, me->CurrentANum);
  3039.         me->CurrentANum = 0;
  3040.         }
  3041.     } else {
  3042.         /*
  3043.          *    Just put in the ALT or pseudo-ALT string
  3044.          *    for the current anchor or inline, with an
  3045.          *    ID link if indicated. - FM
  3046.          */
  3047.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3048.         me->in_word = NO;
  3049.         if (id_string) {
  3050.         if ((ID_A = HTAnchor_findChildAndLink(
  3051.                   me->node_anchor,    /* Parent */
  3052.                   id_string,        /* Tag */
  3053.                   NULL,         /* Addresss */
  3054.                   (HTLinkType*)0)) != NULL) {    /* Type */
  3055.             HText_beginAnchor(me->text, me->inUnderline, ID_A);
  3056.             HText_endAnchor(me->text, 0);
  3057.         }
  3058.         }
  3059.         HTML_put_string(me, alt_string);
  3060.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3061.         me->in_word = NO;
  3062.     }
  3063.     FREE(map_href);
  3064.     FREE(alt_string);
  3065.     FREE(id_string);
  3066.     FREE(title);
  3067.     FREE(newtitle);
  3068.     dest = NULL;
  3069.     dest_ismap = FALSE;
  3070.     break;
  3071.  
  3072.     case HTML_MAP:
  3073.     /*
  3074.      *  Load id_string if we have a NAME or ID. - FM
  3075.      */
  3076.     if (present && present[HTML_MAP_NAME] &&
  3077.         value[HTML_MAP_NAME] && *value[HTML_MAP_NAME]) {
  3078.         StrAllocCopy(id_string, value[HTML_MAP_NAME]);
  3079.     } else if (present && present[HTML_MAP_ID] &&
  3080.            value[HTML_MAP_ID] && *value[HTML_MAP_ID]) {
  3081.         StrAllocCopy(id_string, value[HTML_MAP_ID]);
  3082.     }
  3083.     if (id_string) {
  3084.         TRANSLATE_AND_UNESCAPE_TO_STD(&id_string);
  3085.         if (*id_string == '\0') {
  3086.         FREE(id_string);
  3087.         }
  3088.     }
  3089.  
  3090.     /*
  3091.      *  Load map_address. - FM
  3092.      */
  3093.     if (id_string) {
  3094.         /*
  3095.          *    The MAP must be in the current stream, even if it
  3096.          *    had a BASE tag, so we'll use its address here, but
  3097.          *    still use the BASE, if present, when resolving the
  3098.          *    AREA elements in it's content, unless the AREA's
  3099.          *    HREF is a lone fragment and LYSeekFragAREAinCur is
  3100.          *    set. - FM && KW
  3101.          */
  3102.         StrAllocCopy(me->map_address, me->node_anchor->address);
  3103.         if ((cp = strrchr(me->map_address, '#')) != NULL)
  3104.         *cp = '\0';
  3105.         StrAllocCat(me->map_address, "#");
  3106.         StrAllocCat(me->map_address, id_string);
  3107.         FREE(id_string);
  3108.         if (present && present[HTML_MAP_TITLE] &&
  3109.         value[HTML_MAP_TITLE] && *value[HTML_MAP_TITLE] != '\0') {
  3110.         StrAllocCopy(title, value[HTML_MAP_TITLE]);
  3111.         TRANSLATE_AND_UNESCAPE_ENTITIES(&title, TRUE, FALSE);
  3112.         LYTrimHead(title);
  3113.         LYTrimTail(title);
  3114.         if (*title == '\0') {
  3115.             FREE(title);
  3116.         }
  3117.         }
  3118.         LYAddImageMap(me->map_address, title, me->node_anchor);
  3119.         FREE(title);
  3120.     }
  3121.     break;
  3122.  
  3123.     case HTML_AREA:
  3124.     if (me->map_address &&
  3125.         present && present[HTML_AREA_HREF] &&
  3126.         value[HTML_AREA_HREF] && *value[HTML_AREA_HREF]) {
  3127.         /*
  3128.          *    Resolve the HREF. - FM
  3129.          */
  3130.         StrAllocCopy(href, value[HTML_AREA_HREF]);
  3131.         CHECK_FOR_INTERN(href);
  3132.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  3133.  
  3134.         /*
  3135.          *    Check whether a BASE tag is in effect, and use it
  3136.          *    for resolving, even though we used this stream's
  3137.          *    address for locating the MAP itself, unless the
  3138.          *    HREF is a lone fragment and LYSeekFragAREAinCur
  3139.          *    is set. - FM
  3140.          */
  3141.         if (((me->inBASE && *href != '\0') &&
  3142.          !(*href == '#' && LYSeekFragAREAinCur == TRUE)) &&
  3143.         (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  3144.         *temp != '\0')
  3145.         /*
  3146.          *  Use reference related to the base.
  3147.          */
  3148.         StrAllocCopy(href, temp);
  3149.         FREE(temp);
  3150.  
  3151.         /*
  3152.          *    Check whether to fill in localhost. - FM
  3153.          */
  3154.         LYFillLocalFileURL((char **)&href,
  3155.                    ((((me->inBASE && *href != '\0') &&
  3156.                   !(*href == '#' &&
  3157.                     LYSeekFragAREAinCur == TRUE)))
  3158.                         ?
  3159.                   me->base_href : me->node_anchor->address));
  3160.         if (!(url_type = is_url(href))) {
  3161.         temp = HTParse(href, me->node_anchor->address, PARSE_ALL);
  3162.         if (!(temp && *temp)) {
  3163.            FREE(href);
  3164.            FREE(temp);
  3165.            break;
  3166.         }
  3167.         StrAllocCopy(href, temp);
  3168.         FREE(temp);
  3169.         }
  3170.  
  3171.         /*
  3172.          *    Check for an ALT. - FM
  3173.          */
  3174.         if (present[HTML_AREA_ALT] &&
  3175.         value[HTML_AREA_ALT] && *value[HTML_AREA_ALT]) {
  3176.         StrAllocCopy(alt_string, value[HTML_AREA_ALT]);
  3177.         } else if (present[HTML_AREA_TITLE] &&
  3178.         value[HTML_AREA_TITLE] && *value[HTML_AREA_TITLE]) {
  3179.         /*
  3180.          *  Use the TITLE as an ALT. - FM
  3181.          */
  3182.         StrAllocCopy(alt_string, value[HTML_AREA_TITLE]);
  3183.         }
  3184.         if (alt_string != NULL) {
  3185.         TRANSLATE_AND_UNESCAPE_ENTITIES(&alt_string,
  3186.                                me->UsePlainSpace, me->HiddenValue);
  3187.         /*
  3188.          *  Make sure it's not just space(s). - FM
  3189.          */
  3190.         LYTrimHead(alt_string);
  3191.         LYTrimTail(alt_string);
  3192.         if (*alt_string == '\0') {
  3193.             StrAllocCopy(alt_string, href);
  3194.         }
  3195.         } else {
  3196.         /*
  3197.          *  Use the HREF as an ALT. - FM
  3198.          */
  3199.         StrAllocCopy(alt_string, href);
  3200.         }
  3201.  
  3202.         LYAddMapElement(me->map_address, href, alt_string,
  3203.                 me->node_anchor, intern_flag);
  3204.         FREE(href);
  3205.         FREE(alt_string);
  3206.     }
  3207.     break;
  3208.  
  3209.     case HTML_PARAM:
  3210.     /*
  3211.      *  We may need to look at this someday to deal with
  3212.      *  MAPs, OBJECTs or APPLETs optimally, but just ignore
  3213.      *  it for now. - FM
  3214.      */
  3215.     break;
  3216.  
  3217.     case HTML_BODYTEXT:
  3218.     CHECK_ID(HTML_BODYTEXT_ID);
  3219.     /*
  3220.      *  We may need to look at this someday to deal with
  3221.      *  OBJECTs optimally, but just ignore it for now. - FM
  3222.      */
  3223.     break;
  3224.  
  3225.     case HTML_TEXTFLOW:
  3226.     CHECK_ID(HTML_BODYTEXT_ID);
  3227.     /*
  3228.      *  We may need to look at this someday to deal with
  3229.      *  APPLETs optimally, but just ignore it for now. - FM
  3230.      */
  3231.     break;
  3232.  
  3233.     case HTML_FIG:
  3234.     me->inFIG = TRUE;
  3235.     if (me->inA) {
  3236.         SET_SKIP_STACK(HTML_A);
  3237.         HTML_end_element(me, HTML_A, (char **)&include);
  3238.     }
  3239.     if (!present ||
  3240.         (present && !present[HTML_FIG_ISOBJECT])) {
  3241.         LYEnsureDoubleSpace(me);
  3242.         LYResetParagraphAlignment(me);
  3243.         me->inFIGwithP = TRUE;
  3244.     } else {
  3245.         me->inFIGwithP = FALSE;
  3246.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3247.     }
  3248.     CHECK_ID(HTML_FIG_ID);
  3249.     me->in_word = NO;
  3250.     me->inP = FALSE;
  3251.  
  3252.     if (clickable_images && present && present[HTML_FIG_SRC] &&
  3253.         value[HTML_FIG_SRC] && *value[HTML_FIG_SRC] != '\0') {
  3254.         StrAllocCopy(href, value[HTML_FIG_SRC]);
  3255.         CHECK_FOR_INTERN(href);
  3256.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  3257.         if (*href) {
  3258.         /*
  3259.          *  Check whether a base tag is in effect. - FM
  3260.          */
  3261.         if ((me->inBASE && *href != '#') &&
  3262.             (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  3263.             *temp != '\0')
  3264.             /*
  3265.              *    Use reference related to the base.
  3266.              */
  3267.             StrAllocCopy(href, temp);
  3268.         FREE(temp);
  3269.  
  3270.         /*
  3271.          *  Check whether to fill in localhost. - FM
  3272.          */
  3273.         LYFillLocalFileURL((char **)&href,
  3274.                    ((*href != '#' &&
  3275.                      me->inBASE) ?
  3276.                    me->base_href : me->node_anchor->address));
  3277.  
  3278.         me->CurrentA = HTAnchor_findChildAndLink(
  3279.                     me->node_anchor,    /* Parent */
  3280.                     NULL,            /* Tag */
  3281.                     href,            /* Addresss */
  3282.                     INTERN_LT);        /* Type */
  3283.         HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
  3284.         if (me->inBoldH == FALSE)
  3285.             HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  3286.         HTML_put_string(me, (present[HTML_FIG_ISOBJECT] ?
  3287.               (present[HTML_FIG_IMAGEMAP] ?
  3288.                     "(IMAGE)" : "(OBJECT)") : "[FIGURE]"));
  3289.         if (me->inBoldH == FALSE)
  3290.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3291.         HText_endAnchor(me->text, 0);
  3292.         HTML_put_character(me, '-');
  3293.         HTML_put_character(me, ' '); /* space char may be ignored */
  3294.         me->in_word = NO;
  3295.         }
  3296.         FREE(href);
  3297.     }
  3298.     break;
  3299.  
  3300.     case HTML_OBJECT:
  3301.     if (!me->object_started) {
  3302.         /*
  3303.          *    This is an outer OBJECT start tag,
  3304.          *    i.e., not a nested OBJECT, so save
  3305.          *    it's relevant attributes. - FM
  3306.          */
  3307.         if (present) {
  3308.         if (present[HTML_OBJECT_DECLARE])
  3309.             me->object_declare = TRUE;
  3310.         if (present[HTML_OBJECT_SHAPES])
  3311.             me->object_shapes = TRUE;
  3312.         if (present[HTML_OBJECT_ISMAP])
  3313.             me->object_ismap = TRUE;
  3314.         if (present[HTML_OBJECT_USEMAP] &&
  3315.             value[HTML_OBJECT_USEMAP] && *value[HTML_OBJECT_USEMAP]) {
  3316.             StrAllocCopy(me->object_usemap, value[HTML_OBJECT_USEMAP]);
  3317.             TRANSLATE_AND_UNESCAPE_TO_STD(&me->object_usemap);
  3318.             if (*me->object_usemap == '\0') {
  3319.             FREE(me->object_usemap);
  3320.             }
  3321.         }
  3322.         if (present[HTML_OBJECT_ID] &&
  3323.             value[HTML_OBJECT_ID] && *value[HTML_OBJECT_ID]) {
  3324.             StrAllocCopy(me->object_id, value[HTML_OBJECT_ID]);
  3325.             TRANSLATE_AND_UNESCAPE_TO_STD(&me->object_id);
  3326.             if (*me->object_id == '\0') {
  3327.             FREE(me->object_id);
  3328.             }
  3329.         }
  3330.         if (present[HTML_OBJECT_TITLE] &&
  3331.             value[HTML_OBJECT_TITLE] && *value[HTML_OBJECT_TITLE]) {
  3332.             StrAllocCopy(me->object_title, value[HTML_OBJECT_TITLE]);
  3333.             TRANSLATE_AND_UNESCAPE_ENTITIES(&me->object_title, TRUE, FALSE);
  3334.             LYTrimHead(me->object_title);
  3335.             LYTrimTail(me->object_title);
  3336.             if (me->object_title == '\0') {
  3337.             FREE(me->object_title);
  3338.             }
  3339.         }
  3340.         if (present[HTML_OBJECT_DATA] &&
  3341.             value[HTML_OBJECT_DATA] && *value[HTML_OBJECT_DATA]) {
  3342.             StrAllocCopy(me->object_data, value[HTML_OBJECT_DATA]);
  3343.             TRANSLATE_AND_UNESCAPE_TO_STD(&me->object_data);
  3344.             if (*me->object_data == '\0') {
  3345.             FREE(me->object_data);
  3346.             }
  3347.         }
  3348.         if (present[HTML_OBJECT_TYPE] &&
  3349.             value[HTML_OBJECT_TYPE] && *value[HTML_OBJECT_TYPE]) {
  3350.             StrAllocCopy(me->object_type, value[HTML_OBJECT_TYPE]);
  3351.             TRANSLATE_AND_UNESCAPE_ENTITIES(&me->object_type, TRUE, FALSE);
  3352.             LYTrimHead(me->object_type);
  3353.             LYTrimTail(me->object_type);
  3354.             if (me->object_type == '\0') {
  3355.             FREE(me->object_type);
  3356.             }
  3357.         }
  3358.         if (present[HTML_OBJECT_CLASSID] &&
  3359.             value[HTML_OBJECT_CLASSID] &&
  3360.             *value[HTML_OBJECT_CLASSID]) {
  3361.             StrAllocCopy(me->object_classid,
  3362.                  value[HTML_OBJECT_CLASSID]);
  3363.             TRANSLATE_AND_UNESCAPE_ENTITIES(&me->object_classid, TRUE, FALSE);
  3364.             LYTrimHead(me->object_classid);
  3365.             LYTrimTail(me->object_classid);
  3366.             if (me->object_classid == '\0') {
  3367.             FREE(me->object_classid);
  3368.             }
  3369.         }
  3370.         if (present[HTML_OBJECT_CODEBASE] &&
  3371.             value[HTML_OBJECT_CODEBASE] &&
  3372.             *value[HTML_OBJECT_CODEBASE]) {
  3373.             StrAllocCopy(me->object_codebase,
  3374.                  value[HTML_OBJECT_CODEBASE]);
  3375.             TRANSLATE_AND_UNESCAPE_TO_STD(&me->object_codebase);
  3376.             if (*me->object_codebase == '\0') {
  3377.             FREE(me->object_codebase);
  3378.             }
  3379.         }
  3380.         if (present[HTML_OBJECT_CODETYPE] &&
  3381.             value[HTML_OBJECT_CODETYPE] &&
  3382.             *value[HTML_OBJECT_CODETYPE]) {
  3383.             StrAllocCopy(me->object_codetype,
  3384.                  value[HTML_OBJECT_CODETYPE]);
  3385.             TRANSLATE_AND_UNESCAPE_ENTITIES(&me->object_codetype, TRUE, FALSE);
  3386.             LYTrimHead(me->object_codetype);
  3387.             LYTrimTail(me->object_codetype);
  3388.             if (me->object_codetype == '\0') {
  3389.             FREE(me->object_codetype);
  3390.             }
  3391.         }
  3392.         if (present[HTML_OBJECT_NAME] &&
  3393.             value[HTML_OBJECT_NAME] && *value[HTML_OBJECT_NAME]) {
  3394.             StrAllocCopy(me->object_name, value[HTML_OBJECT_NAME]);
  3395.             TRANSLATE_AND_UNESCAPE_ENTITIES(&me->object_name, TRUE, FALSE);
  3396.             LYTrimHead(me->object_name);
  3397.             LYTrimTail(me->object_name);
  3398.             if (me->object_name == '\0') {
  3399.             FREE(me->object_name);
  3400.             }
  3401.         }
  3402.         }
  3403.         /*
  3404.          *    Set flag that we are accumulating OBJECT content. - FM
  3405.          */
  3406.         me->object_started = TRUE;
  3407.     }
  3408.     break;
  3409.  
  3410.     case HTML_OVERLAY:
  3411.     if (clickable_images && me->inFIG &&
  3412.         present && present[HTML_OVERLAY_SRC] &&
  3413.         value[HTML_OVERLAY_SRC] && *value[HTML_OVERLAY_SRC] != '\0') {
  3414.         StrAllocCopy(href, value[HTML_OVERLAY_SRC]);
  3415.         CHECK_FOR_INTERN(href);
  3416.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  3417.         if (*href) {
  3418.         /*
  3419.          *  Check whether a base tag is in effect. - FM
  3420.          */
  3421.         if ((me->inBASE && *href != '#') &&
  3422.             (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  3423.             *temp != '\0')
  3424.             /*
  3425.              *    Use reference related to the base.
  3426.              */
  3427.             StrAllocCopy(href, temp);
  3428.         FREE(temp);
  3429.  
  3430.         /*
  3431.          *  Check whether to fill in localhost. - FM
  3432.          */
  3433.         LYFillLocalFileURL((char **)&href,
  3434.                    ((*href != '#' &&
  3435.                      me->inBASE) ?
  3436.                    me->base_href : me->node_anchor->address));
  3437.  
  3438.         if (me->inA) {
  3439.             SET_SKIP_STACK(HTML_A);
  3440.             HTML_end_element(me, HTML_A, (char **)&include);
  3441.         }
  3442.         me->CurrentA = HTAnchor_findChildAndLink(
  3443.                     me->node_anchor,    /* Parent */
  3444.                     NULL,            /* Tag */
  3445.                     href,            /* Addresss */
  3446.                     INTERN_LT);        /* Type */
  3447.         HTML_put_character(me, ' ');
  3448.         HText_appendCharacter(me->text, '+');
  3449.         me->CurrentANum = HText_beginAnchor(me->text,
  3450.                             me->inUnderline,
  3451.                             me->CurrentA);
  3452.         if (me->inBoldH == FALSE)
  3453.             HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  3454.         HTML_put_string(me, "[OVERLAY]");
  3455.         if (me->inBoldH == FALSE)
  3456.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3457.         HText_endAnchor(me->text, me->CurrentANum);
  3458.         HTML_put_character(me, ' ');
  3459.         me->in_word = NO;
  3460.         }
  3461.         FREE(href);
  3462.     }
  3463.     break;
  3464.  
  3465.     case HTML_APPLET:
  3466.     me->inAPPLET = TRUE;
  3467.     me->inAPPLETwithP = FALSE;
  3468.     HTML_put_character(me, ' ');  /* space char may be ignored */
  3469.     /*
  3470.      *  Load id_string if we have an ID or NAME. - FM
  3471.      */
  3472.     if (present && present[HTML_APPLET_ID] &&
  3473.         value[HTML_APPLET_ID] && *value[HTML_APPLET_ID]) {
  3474.         StrAllocCopy(id_string, value[HTML_APPLET_ID]);
  3475.     } else if (present && present[HTML_APPLET_NAME] &&
  3476.            value[HTML_APPLET_NAME] && *value[HTML_APPLET_NAME]) {
  3477.         StrAllocCopy(id_string, value[HTML_APPLET_NAME]);
  3478.     }
  3479.     if (id_string) {
  3480.         TRANSLATE_AND_UNESCAPE_TO_STD(&id_string);
  3481.         LYHandleID(me, id_string);
  3482.         FREE(id_string);
  3483.     }
  3484.     me->in_word = NO;
  3485.  
  3486.     /*
  3487.      *  If there's an ALT string, use it, unless the ALT string
  3488.      *  is zero-length and we are making all sources links. - FM
  3489.      */
  3490.     if (present && present[HTML_APPLET_ALT] && value[HTML_APPLET_ALT] &&
  3491.         (!clickable_images ||
  3492.          (clickable_images && *value[HTML_APPLET_ALT] != '\0'))) {
  3493.         StrAllocCopy(alt_string, value[HTML_APPLET_ALT]);
  3494.         TRANSLATE_AND_UNESCAPE_ENTITIES(&alt_string,
  3495.                            me->UsePlainSpace, me->HiddenValue);
  3496.         /*
  3497.          *    If it's all spaces and we are making sources links,
  3498.          *    treat it as zero-length. - FM
  3499.          */
  3500.         if (clickable_images) {
  3501.         LYTrimHead(alt_string);
  3502.         LYTrimTail(alt_string);
  3503.         if (*alt_string == '\0') {
  3504.             StrAllocCopy(alt_string, "[APPLET]");
  3505.         }
  3506.         }
  3507.  
  3508.     } else {
  3509.         if (clickable_images)
  3510.         StrAllocCopy(alt_string, "[APPLET]");
  3511.         else
  3512.         StrAllocCopy(alt_string, "");
  3513.     }
  3514.  
  3515.     /*
  3516.      *  If we're making all sources links, get the source. - FM
  3517.      */
  3518.     if (clickable_images && present && present[HTML_APPLET_CODE] &&
  3519.         value[HTML_APPLET_CODE] && *value[HTML_APPLET_CODE] != '\0') {
  3520.         char * base = NULL;
  3521.         char * code = NULL;
  3522.  
  3523.         /*
  3524.          *    Check for a CODEBASE attribute. - FM
  3525.          */
  3526.         if (present[HTML_APPLET_CODEBASE] &&
  3527.         value[HTML_APPLET_CODEBASE] && *value[HTML_APPLET_CODEBASE]) {
  3528.         StrAllocCopy(base, value[HTML_APPLET_CODEBASE]);
  3529.         LYRemoveBlanks(base);
  3530.         TRANSLATE_AND_UNESCAPE_TO_STD(&base);
  3531.         /*
  3532.          *  Force it to be a directory. - FM
  3533.          */
  3534.         if (*base == '\0')
  3535.             StrAllocCopy(base, "/");
  3536.         if (base[strlen(base)-1] != '/')
  3537.             StrAllocCat(base, "/");
  3538.         url_type = LYLegitimizeHREF(me, (char**)&base, TRUE, FALSE);
  3539.  
  3540.         /*
  3541.          *  Check whether to fill in localhost. - FM
  3542.          */
  3543.         LYFillLocalFileURL((char **)&base,
  3544.                    (me->inBASE ?
  3545.                  me->base_href : me->node_anchor->address));
  3546.  
  3547.         if (!(url_type = is_url(base))) {
  3548.             /*
  3549.              *    Check whether a base tag is in effect.
  3550.              */
  3551.             if (me->inBASE) {
  3552.             temp = HTParse(base, me->base_href, PARSE_ALL);
  3553.             } else {
  3554.             temp = HTParse(base, me->node_anchor->address,
  3555.                             PARSE_ALL);
  3556.             }
  3557.             StrAllocCopy(base, temp);
  3558.             FREE(temp);
  3559.         }
  3560.         } else {
  3561.         if (me->inBASE) {
  3562.             StrAllocCopy(base, me->base_href);
  3563.         } else {
  3564.             StrAllocCopy(base, me->node_anchor->address);
  3565.         }
  3566.         }
  3567.  
  3568.         StrAllocCopy(code, value[HTML_APPLET_CODE]);
  3569.         url_type = LYLegitimizeHREF(me, (char**)&code, TRUE, FALSE);
  3570.         href = HTParse(code, base, PARSE_ALL);
  3571.         FREE(base);
  3572.         FREE(code);
  3573.  
  3574.         if (href && *href) {
  3575.         if (me->inA) {
  3576.             if (me->inBoldA == TRUE && me->inBoldH == FALSE)
  3577.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3578.             HText_endAnchor(me->text, me->CurrentANum);
  3579.             HTML_put_character(me, '-');
  3580.         }
  3581.         me->CurrentA = HTAnchor_findChildAndLink(
  3582.                     me->node_anchor,    /* Parent */
  3583.                     NULL,            /* Tag */
  3584.                     href,            /* Addresss */
  3585.                     (HTLinkType*)0);    /* Type */
  3586.         me->CurrentANum = HText_beginAnchor(me->text,
  3587.                             me->inUnderline,
  3588.                             me->CurrentA);
  3589.         if (me->inBoldH == FALSE)
  3590.             HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  3591.         HTML_put_string(me, alt_string);
  3592.         if (me->inA == FALSE) {
  3593.             if (me->inBoldH == FALSE)
  3594.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3595.             HText_endAnchor(me->text, me->CurrentANum);
  3596.             me->CurrentANum = 0;
  3597.         }
  3598.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3599.         me->in_word = NO;
  3600.         }
  3601.         FREE(href);
  3602.     } else if (*alt_string) {
  3603.         /*
  3604.          *    Just put up the ALT string, if non-zero. - FM
  3605.          */
  3606.         HTML_put_string(me, alt_string);
  3607.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3608.         me->in_word = NO;
  3609.     }
  3610.     FREE(alt_string);
  3611.     FREE(id_string);
  3612.     break;
  3613.  
  3614.     case HTML_BGSOUND:
  3615.     /*
  3616.      *  If we're making all sources links, get the source. - FM
  3617.      */
  3618.     if (clickable_images && present && present[HTML_BGSOUND_SRC] &&
  3619.         value[HTML_BGSOUND_SRC] && *value[HTML_BGSOUND_SRC] != '\0') {
  3620.         StrAllocCopy(href, value[HTML_BGSOUND_SRC]);
  3621.         CHECK_FOR_INTERN(href);
  3622.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  3623.         if (*href == '\0') {
  3624.         FREE(href);
  3625.         break;
  3626.         }
  3627.  
  3628.         /*
  3629.          *    Check whether a base tag is in effect. - FM
  3630.          */
  3631.         if ((me->inBASE && *href != '#') &&
  3632.         (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  3633.         *temp != '\0')
  3634.         /*
  3635.          *  Use reference related to the base.
  3636.          */
  3637.         StrAllocCopy(href, temp);
  3638.         FREE(temp);
  3639.  
  3640.         /*
  3641.          *    Check whether to fill in localhost. - FM
  3642.          */
  3643.         LYFillLocalFileURL((char **)&href,
  3644.                    ((*href != '#' &&
  3645.                  me->inBASE) ?
  3646.                    me->base_href : me->node_anchor->address));
  3647.  
  3648.         if (me->inA) {
  3649.         if (me->inBoldA == TRUE && me->inBoldH == FALSE)
  3650.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3651.         HText_endAnchor(me->text, me->CurrentANum);
  3652.         HTML_put_character(me, '-');
  3653.         } else {
  3654.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3655.         me->in_word = NO;
  3656.         }
  3657.         me->CurrentA = HTAnchor_findChildAndLink(
  3658.                     me->node_anchor,    /* Parent */
  3659.                     NULL,            /* Tag */
  3660.                     href,            /* Addresss */
  3661.                     INTERN_LT);        /* Type */
  3662.         me->CurrentANum = HText_beginAnchor(me->text,
  3663.                         me->inUnderline,
  3664.                         me->CurrentA);
  3665.         if (me->inBoldH == FALSE)
  3666.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  3667.         HTML_put_string(me, "[BGSOUND]");
  3668.         if (me->inA == FALSE) {
  3669.         if (me->inBoldH == FALSE)
  3670.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3671.         HText_endAnchor(me->text, me->CurrentANum);
  3672.         me->CurrentANum = 0;
  3673.         }
  3674.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3675.         me->in_word = NO;
  3676.         FREE(href);
  3677.     }
  3678.     break;
  3679.  
  3680.     case HTML_EMBED:
  3681.     if (pseudo_inline_alts || clickable_images)
  3682.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3683.     /*
  3684.      *  Load id_string if we have an ID or NAME. - FM
  3685.      */
  3686.     if (present && present[HTML_EMBED_ID] &&
  3687.         value[HTML_EMBED_ID] && *value[HTML_EMBED_ID]) {
  3688.         StrAllocCopy(id_string, value[HTML_EMBED_ID]);
  3689.     } else if (present && present[HTML_EMBED_NAME] &&
  3690.            value[HTML_EMBED_NAME] && *value[HTML_EMBED_NAME]) {
  3691.         StrAllocCopy(id_string, value[HTML_EMBED_NAME]);
  3692.     }
  3693.     if (id_string) {
  3694.         TRANSLATE_AND_UNESCAPE_TO_STD(&id_string);
  3695.         LYHandleID(me, id_string);
  3696.         FREE(id_string);
  3697.     }
  3698.     if (pseudo_inline_alts || clickable_images)
  3699.         me->in_word = NO;
  3700.  
  3701.     /*
  3702.      *  If there's an ALT string, use it, unless the ALT string
  3703.      *  is zero-length and we are making all sources links. - FM
  3704.      */
  3705.     if (present && present[HTML_EMBED_ALT] && value[HTML_EMBED_ALT] &&
  3706.         (!clickable_images ||
  3707.          (clickable_images && *value[HTML_EMBED_ALT] != '\0'))) {
  3708.         StrAllocCopy(alt_string, value[HTML_EMBED_ALT]);
  3709.         TRANSLATE_AND_UNESCAPE_ENTITIES(&alt_string,
  3710.                            me->UsePlainSpace, me->HiddenValue);
  3711.         /*
  3712.          *    If it's all spaces and we are making sources links,
  3713.          *    treat it as zero-length. - FM
  3714.          */
  3715.         if (clickable_images) {
  3716.         LYTrimHead(alt_string);
  3717.         LYTrimTail(alt_string);
  3718.         if (*alt_string == '\0') {
  3719.             StrAllocCopy(alt_string, "[EMBED]");
  3720.         }
  3721.         }
  3722.     } else {
  3723.         if (pseudo_inline_alts || clickable_images)
  3724.         StrAllocCopy(alt_string, "[EMBED]");
  3725.         else
  3726.         StrAllocCopy(alt_string, "");
  3727.     }
  3728.  
  3729.     /*
  3730.      *  If we're making all sources links, get the source. - FM
  3731.      */
  3732.     if (clickable_images && present && present[HTML_EMBED_SRC] &&
  3733.         value[HTML_EMBED_SRC] && *value[HTML_EMBED_SRC] != '\0') {
  3734.         StrAllocCopy(href, value[HTML_EMBED_SRC]);
  3735.         CHECK_FOR_INTERN(href);
  3736.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  3737.         if (*href != '\0') {
  3738.         /*
  3739.          *  Check whether a base tag is in effect. - FM
  3740.          */
  3741.         if ((me->inBASE && *href != '#') &&
  3742.             (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  3743.             *temp != '\0')
  3744.             /*
  3745.              *    Use reference related to the base.
  3746.              */
  3747.             StrAllocCopy(href, temp);
  3748.         FREE(temp);
  3749.  
  3750.         /*
  3751.          *  Check whether to fill in localhost. - FM
  3752.          */
  3753.         LYFillLocalFileURL((char **)&href,
  3754.                    ((*href != '#' &&
  3755.                      me->inBASE) ?
  3756.                    me->base_href : me->node_anchor->address));
  3757.  
  3758.         if (me->inA) {
  3759.             if (me->inBoldA == TRUE && me->inBoldH == FALSE)
  3760.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3761.             HText_endAnchor(me->text, me->CurrentANum);
  3762.             HTML_put_character(me, '-');
  3763.         }
  3764.         me->CurrentA = HTAnchor_findChildAndLink(
  3765.                     me->node_anchor,    /* Parent */
  3766.                     NULL,            /* Tag */
  3767.                     href,            /* Addresss */
  3768.                     INTERN_LT);        /* Type */
  3769.         me->CurrentANum = HText_beginAnchor(me->text,
  3770.                             me->inUnderline,
  3771.                             me->CurrentA);
  3772.         if (me->inBoldH == FALSE)
  3773.             HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  3774.         HTML_put_string(me, alt_string);
  3775.         if (me->inBoldH == FALSE)
  3776.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3777.         if (me->inA == FALSE) {
  3778.             if (me->inBoldH == FALSE)
  3779.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  3780.             HText_endAnchor(me->text, me->CurrentANum);
  3781.             me->CurrentANum = 0;
  3782.         }
  3783.         HTML_put_character(me, ' ');
  3784.         me->in_word = NO;
  3785.         }
  3786.         FREE(href);
  3787.     } else if (*alt_string) {
  3788.         /*
  3789.          *    Just put up the ALT string, if non-zero. - FM
  3790.          */
  3791.         HTML_put_string(me, alt_string);
  3792.         HTML_put_character(me, ' ');  /* space char may be ignored */
  3793.         me->in_word = NO;
  3794.     }
  3795.     FREE(alt_string);
  3796.     FREE(id_string);
  3797.     break;
  3798.  
  3799.     case HTML_CREDIT:
  3800.     LYEnsureDoubleSpace(me);
  3801.     LYResetParagraphAlignment(me);
  3802.     me->inCREDIT = TRUE;
  3803.     CHECK_ID(HTML_CREDIT_ID);
  3804.     if (me->inUnderline == FALSE)
  3805.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  3806.     HTML_put_string(me, "CREDIT:");
  3807.     if (me->inUnderline == FALSE)
  3808.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  3809.     HTML_put_character(me, ' ');
  3810.  
  3811.     if (me->inFIG)
  3812.         /*
  3813.          *    Assume all text in the FIG container is intended
  3814.          *    to be paragraphed. - FM
  3815.          */
  3816.         me->inFIGwithP = TRUE;
  3817.  
  3818.     if (me->inAPPLET)
  3819.         /*
  3820.          *    Assume all text in the APPLET container is intended
  3821.          *    to be paragraphed. - FM
  3822.          */
  3823.         me->inAPPLETwithP = TRUE;
  3824.  
  3825.     me->inLABEL = TRUE;
  3826.     me->in_word = NO;
  3827.     me->inP = FALSE;
  3828.     break;
  3829.  
  3830.     case HTML_CAPTION:
  3831.     LYEnsureDoubleSpace(me);
  3832.     LYResetParagraphAlignment(me);
  3833.     me->inCAPTION = TRUE;
  3834.     CHECK_ID(HTML_CAPTION_ID);
  3835.     if (me->inUnderline == FALSE)
  3836.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  3837.     HTML_put_string(me, "CAPTION:");
  3838.     if (me->inUnderline == FALSE)
  3839.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  3840.     HTML_put_character(me, ' ');
  3841.  
  3842.     if (me->inFIG)
  3843.         /*
  3844.          *    Assume all text in the FIG container is intended
  3845.          *    to be paragraphed. - FM
  3846.          */
  3847.         me->inFIGwithP = TRUE;
  3848.  
  3849.     if (me->inAPPLET)
  3850.         /*
  3851.          *    Assume all text in the APPLET container is intended
  3852.          *    to be paragraphed. - FM
  3853.          */
  3854.         me->inAPPLETwithP = TRUE;
  3855.  
  3856.     me->inLABEL = TRUE;
  3857.     me->in_word = NO;
  3858.     me->inP = FALSE;
  3859.     break;
  3860.  
  3861.     case HTML_FORM:
  3862.     {
  3863.         char * action = NULL;
  3864.         char * method = NULL;
  3865.         char * enctype = NULL;
  3866.         CONST char * accept_cs = NULL;
  3867.  
  3868.         HTChildAnchor * source;
  3869.         HTAnchor *link_dest;
  3870.  
  3871.         /*
  3872.          *    FORM may have been declared SGML_EMPTY in HTMLDTD.c, and
  3873.          *    SGML_character() in SGML.c may check for a FORM end
  3874.          *    tag to call HTML_end_element() directly (with a
  3875.          *    check in that to bypass decrementing of the HTML
  3876.          *    parser's stack), so if we have an open FORM, close
  3877.          *    that one now. - FM
  3878.          */
  3879.         if (me->inFORM) {
  3880.         CTRACE(tfp, "HTML: Missing FORM end tag. Faking it!\n");
  3881.         SET_SKIP_STACK(HTML_FORM);
  3882.         HTML_end_element(me, HTML_FORM, (char **)&include);
  3883.         }
  3884.  
  3885.         /*
  3886.          *    Set to know we are in a new form.
  3887.          */
  3888.         me->inFORM = TRUE;
  3889.  
  3890.         if (present && present[HTML_FORM_ACCEPT_CHARSET]) {
  3891.         accept_cs = value[HTML_FORM_ACCEPT_CHARSET] ?
  3892.                 value[HTML_FORM_ACCEPT_CHARSET] : "UNKNOWN";
  3893.         }
  3894.         if (present && present[HTML_FORM_ACTION] &&
  3895.         value[HTML_FORM_ACTION])  {
  3896.         /*
  3897.          *  Prepare to do housekeeping on the reference. - FM
  3898.          */
  3899.         StrAllocCopy(action, value[HTML_FORM_ACTION]);
  3900.         url_type = LYLegitimizeHREF(me, (char**)&action, TRUE, TRUE);
  3901.  
  3902.         /*
  3903.          *  Check whether a base tag is in effect.  Note that
  3904.          *  actions always are resolved w.r.t. to the base,
  3905.          *  even if the action is empty. - FM
  3906.          */
  3907.         if ((me->inBASE && me->base_href && *me->base_href) &&
  3908.             (temp = HTParse(action, me->base_href, PARSE_ALL)) &&
  3909.             *temp != '\0') {
  3910.             /*
  3911.              *    Use action related to the base.
  3912.              */
  3913.             StrAllocCopy(action, temp);
  3914.         } else if ((temp = HTParse(action,
  3915.                        me->node_anchor->address,
  3916.                        PARSE_ALL)) &&
  3917.             *temp != '\0') {
  3918.             /*
  3919.              *    Use action related to the current document.
  3920.              */
  3921.             StrAllocCopy(action, temp);
  3922.         } else {
  3923.             FREE(action);
  3924.         }
  3925.         FREE(temp);
  3926.         }
  3927.         if (!(action && *action)) {
  3928.         if (me->inBASE && me->base_href && *me->base_href) {
  3929.              StrAllocCopy(action, me->base_href);
  3930.         } else {
  3931.              StrAllocCopy(action, me->node_anchor->address);
  3932.         }
  3933.         }
  3934.         if (action) {
  3935.         source = HTAnchor_findChildAndLink(me->node_anchor,
  3936.                            NULL,
  3937.                            action,
  3938.                            (HTLinkType*)0);
  3939.         if ((link_dest = HTAnchor_followMainLink((HTAnchor *)source)) != NULL) {
  3940.             /*
  3941.              *    Memory leak fixed.
  3942.              *    05-28-94 Lynx 2-3-1 Garrett Arch Blythe
  3943.              */
  3944.             auto char *cp_freeme = HTAnchor_address(link_dest);
  3945.             if (cp_freeme != NULL) {
  3946.             StrAllocCopy(action, cp_freeme);
  3947.             FREE(cp_freeme);
  3948.             } else {
  3949.             StrAllocCopy(action, "");
  3950.             }
  3951.         }
  3952.         }
  3953.  
  3954.         if (present && present[HTML_FORM_METHOD])
  3955.         StrAllocCopy(method, value[HTML_FORM_METHOD] ?
  3956.                      value[HTML_FORM_METHOD] : "GET");
  3957.  
  3958.         if (present && present[HTML_FORM_ENCTYPE] &&
  3959.         value[HTML_FORM_ENCTYPE] && *value[HTML_FORM_ENCTYPE]) {
  3960.         StrAllocCopy(enctype, value[HTML_FORM_ENCTYPE]);
  3961.         LYLowerCase(enctype);
  3962.         }
  3963.  
  3964.         if (present) {
  3965.         /*
  3966.          *  Check for a TITLE attribute, and if none is present,
  3967.          *  check for a SUBJECT attribute as a synonym. - FM
  3968.          */
  3969.         if (present[HTML_FORM_TITLE] &&
  3970.             value[HTML_FORM_TITLE] &&
  3971.             *value[HTML_FORM_TITLE] != '\0') {
  3972.             StrAllocCopy(title, value[HTML_FORM_TITLE]);
  3973.         } else if (present[HTML_FORM_SUBJECT] &&
  3974.                value[HTML_FORM_SUBJECT] &&
  3975.                *value[HTML_FORM_SUBJECT] != '\0') {
  3976.             StrAllocCopy(title, value[HTML_FORM_SUBJECT]);
  3977.         }
  3978.         if (title != NULL && *title != '\0') {
  3979.             TRANSLATE_AND_UNESCAPE_ENTITIES(&title, TRUE, FALSE);
  3980.             LYTrimHead(title);
  3981.             LYTrimTail(title);
  3982.             if (*title == '\0') {
  3983.             FREE(title);
  3984.             }
  3985.         }
  3986.         }
  3987.  
  3988.         HText_beginForm(action, method, enctype, title, accept_cs);
  3989.  
  3990.         FREE(action);
  3991.         FREE(method);
  3992.         FREE(enctype);
  3993.         FREE(title);
  3994.     }
  3995.     CHECK_ID(HTML_FORM_ID);
  3996.     break;
  3997.  
  3998.     case HTML_FIELDSET:
  3999.     LYEnsureDoubleSpace(me);
  4000.     LYResetParagraphAlignment(me);
  4001.     CHECK_ID(HTML_FIELDSET_ID);
  4002.     break;
  4003.  
  4004.     case HTML_LEGEND:
  4005.     LYEnsureDoubleSpace(me);
  4006.     LYResetParagraphAlignment(me);
  4007.     CHECK_ID(HTML_LEGEND_ID);
  4008.     break;
  4009.  
  4010.     case HTML_LABEL:
  4011.     CHECK_ID(HTML_LABEL_ID);
  4012.     break;
  4013.  
  4014.     case HTML_KEYGEN:
  4015.     CHECK_ID(HTML_KEYGEN_ID);
  4016.     break;
  4017.  
  4018.     case HTML_BUTTON:
  4019.     {
  4020.         InputFieldData I;
  4021.         int chars;
  4022.  
  4023.         /* init */
  4024.         I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL;
  4025.         I.disabled=NO; I.error=NULL; I.height= NULL; I.id=NULL;
  4026.         I.lang=NULL; I.max=NULL; I.maxlength=NULL; I.md=NULL;
  4027.         I.min=NULL; I.name=NULL; I.size=NULL; I.src=NULL;
  4028.         I.type=NULL; I.value=NULL; I.width=NULL;
  4029.         I.accept_cs = NULL;
  4030.         I.name_cs = ATTR_CS_IN;
  4031.         I.value_cs = ATTR_CS_IN;
  4032.  
  4033.         UPDATE_STYLE;
  4034.         if ((present && present[HTML_BUTTON_TYPE] &&
  4035.          value[HTML_BUTTON_TYPE]) &&
  4036.         (!strcasecomp(value[HTML_BUTTON_TYPE], "submit") ||
  4037.          !strcasecomp(value[HTML_BUTTON_TYPE], "reset"))) {
  4038.         /*
  4039.          *  It's a button for submitting or resetting a form. - FM
  4040.          */
  4041.         I.type = value[HTML_BUTTON_TYPE];
  4042.         } else {
  4043.         /*
  4044.          *  Ugh, it's a button for a script. - FM
  4045.          */
  4046.         HTML_put_string(me," [BUTTON] ");
  4047.         break;
  4048.         }
  4049.  
  4050.         /*
  4051.          *    Make sure we're in a form.
  4052.          */
  4053.         if (!me->inFORM) {
  4054.         if (TRACE) {
  4055.             fprintf(tfp,
  4056.                 "Bad HTML: BUTTON tag not within FORM tag\n");
  4057.         } else if (!me->inBadHTML) {
  4058.             _statusline(BAD_HTML_USE_TRACE);
  4059.             me->inBadHTML = TRUE;
  4060.             sleep(MessageSecs);
  4061.         }
  4062.         /*
  4063.          *  We'll process it, since the chances of a crash are
  4064.          *  small, and we probably do have a form started. - FM
  4065.          *
  4066.         break;
  4067.          */
  4068.         }
  4069.  
  4070.         /*
  4071.          *    Before any input field, add a collapsible space if
  4072.          *    we're not in a PRE block, to promote a wrap there
  4073.          *    for any long values that would extent past the right
  4074.          *    margin from our current position in the line.  If
  4075.          *    we are in a PRE block, start a new line if the last
  4076.          *    line already is within 6 characters of the wrap point
  4077.          *    for PRE blocks. - FM
  4078.          */
  4079.         if (me->sp[0].tag_number != HTML_PRE && !me->inPRE &&
  4080.         me->sp->style->freeFormat) {
  4081.         HTML_put_character(me, ' ');
  4082.         me->in_word = NO;
  4083.         } else if (HText_LastLineSize(me->text, FALSE) > (LYcols - 7)) {
  4084.         HTML_put_character(me, '\n');
  4085.         me->in_word = NO;
  4086.         }
  4087.         HTML_put_character(me, '(');
  4088.  
  4089.         if (!(present && present[HTML_BUTTON_NAME] &&
  4090.           value[HTML_BUTTON_NAME])) {
  4091.         I.name = "";
  4092.         } else if (strchr(value[HTML_BUTTON_NAME], '&') == NULL) {
  4093.         I.name = value[HTML_BUTTON_NAME];
  4094.         } else {
  4095.         StrAllocCopy(I_name, value[HTML_BUTTON_NAME]);
  4096.         UNESCAPE_FIELDNAME_TO_STD(&I_name);
  4097.         I.name = I_name;
  4098.         }
  4099.  
  4100.         if (present && present[HTML_BUTTON_VALUE] &&
  4101.         value[HTML_BUTTON_VALUE] && *value[HTML_BUTTON_VALUE]) {
  4102.         /*
  4103.          *  Convert any HTML entities or decimal escaping. - FM
  4104.          */
  4105.         int len;
  4106.  
  4107.         StrAllocCopy(I_value, value[HTML_BUTTON_VALUE]);
  4108.         me->UsePlainSpace = TRUE;
  4109.         TRANSLATE_AND_UNESCAPE_ENTITIES(&I_value, TRUE, me->HiddenValue);
  4110.         me->UsePlainSpace = FALSE;
  4111.         I.value = I_value;
  4112.         /*
  4113.          *  Convert any newlines or tabs to spaces,
  4114.          *  and trim any lead or trailing spaces. - FM
  4115.          */
  4116.         convert_to_spaces(I.value, FALSE);
  4117.         while (I.value && I.value[0] == ' ')
  4118.             I.value++;
  4119.         len = strlen(I.value) - 1;
  4120.         while (len > 0 && I.value[len] == ' ')
  4121.             I.value[len--] = '\0';
  4122.         }
  4123.  
  4124.         if (present && present[HTML_BUTTON_DISABLED])
  4125.         I.disabled = YES;
  4126.  
  4127.         if (present && present[HTML_BUTTON_CLASS] && /* Not yet used. */
  4128.         value[HTML_BUTTON_CLASS] && *value[HTML_BUTTON_CLASS])
  4129.         I.class = value[HTML_BUTTON_CLASS];
  4130.  
  4131.         if (present && present[HTML_BUTTON_ID] &&
  4132.         value[HTML_BUTTON_ID] && *value[HTML_BUTTON_ID]) {
  4133.         I.id = value[HTML_BUTTON_ID];
  4134.         CHECK_ID(HTML_BUTTON_ID);
  4135.         }
  4136.  
  4137.         if (present && present[HTML_BUTTON_LANG] && /* Not yet used. */
  4138.         value[HTML_BUTTON_LANG] && *value[HTML_BUTTON_LANG])
  4139.         I.lang = value[HTML_BUTTON_LANG];
  4140.  
  4141.         chars = HText_beginInput(me->text, me->inUnderline, &I);
  4142.         /*
  4143.          *    Submit and reset buttons have values which don't change,
  4144.          *    so HText_beginInput() sets I.value to the string which
  4145.          *    should be displayed, and we'll enter that instead of
  4146.          *    underscore placeholders into the HText structure to
  4147.          *    see it instead of underscores when dumping or printing.
  4148.          *    We also won't worry about a wrap in PRE blocks, because
  4149.          *    the line editor never is invoked for submit or reset
  4150.          *    buttons. - LE & FM
  4151.          */
  4152.         if (me->sp[0].tag_number == HTML_PRE ||
  4153.             !me->sp->style->freeFormat) {
  4154.         /*
  4155.          *  We have a submit or reset button in a PRE block,
  4156.          *  so output the entire value from the markup.  If
  4157.          *  it extends to the right margin, it will wrap
  4158.          *  there, and only the portion before that wrap will
  4159.          *  be hightlighted on screen display (Yuk!) but we
  4160.          *  may as well show the rest of the full value on
  4161.          *  the next or more lines. - FM
  4162.          */
  4163.         while (I.value[i])
  4164.             HTML_put_character(me, I.value[i++]);
  4165.         } else {
  4166.         /*
  4167.          *  The submit or reset button is not in a PRE block.
  4168.          *  Note that if a wrap occurs before outputting the
  4169.          *  entire value, the wrapped portion will not be
  4170.          *  highlighted or clearly indicated as part of the
  4171.          *  link for submission or reset (Yuk!).
  4172.          *  We'll replace any spaces in the submit or reset
  4173.          *  button value with nbsp, to promote a wrap at the
  4174.          *  space we ensured would be present before the start
  4175.          *  of the string, as when we use all underscores
  4176.          *  instead of the INPUT's actual value, but we could
  4177.          *  still get a wrap at the right margin, instead, if
  4178.          *  the value is greater than a line width for the
  4179.          *  current style.  Also, if chars somehow ended up
  4180.          *  longer than the length of the actual value
  4181.          *  (shouldn't have), we'll continue padding with nbsp
  4182.          *  up to the length of chars. - FM
  4183.          */
  4184.         for (i = 0; I.value[i]; i++) {
  4185.             HTML_put_character(me,
  4186.                        (I.value[i] ==  ' ' ?
  4187.                     HT_NON_BREAK_SPACE : I.value[i]));
  4188.         }
  4189.         while (i < chars) {
  4190.             HTML_put_character(me, HT_NON_BREAK_SPACE);
  4191.         }
  4192.         }
  4193.         HTML_put_character(me, ')');
  4194.         if (me->sp[0].tag_number != HTML_PRE &&
  4195.         me->sp->style->freeFormat) {
  4196.         HTML_put_character(me, ' ');
  4197.         me->in_word = NO;
  4198.         }
  4199.         FREE(I_value);
  4200.         FREE(I_name);
  4201.     }
  4202.     break;
  4203.  
  4204.     case HTML_INPUT:
  4205.     {
  4206.         InputFieldData I;
  4207.         int chars;
  4208.         BOOL UseALTasVALUE = FALSE;
  4209.         BOOL HaveSRClink = FALSE;
  4210.         BOOL IsSubmitOrReset = FALSE;
  4211.  
  4212.         /* init */
  4213.         I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL;
  4214.         I.disabled=NO; I.error=NULL; I.height= NULL; I.id=NULL;
  4215.         I.lang=NULL; I.max=NULL; I.maxlength=NULL; I.md=NULL;
  4216.         I.min=NULL; I.name=NULL; I.size=NULL; I.src=NULL;
  4217.         I.type=NULL; I.value=NULL; I.width=NULL;
  4218.         I.accept_cs = NULL;
  4219.         I.name_cs = ATTR_CS_IN;
  4220.         I.value_cs = ATTR_CS_IN;
  4221.  
  4222.         UPDATE_STYLE;
  4223.  
  4224.         /*
  4225.          *    Before any input field, add a collapsible space if
  4226.          *    we're not in a PRE block, to promote a wrap there
  4227.          *    for any long values that would extent past the right
  4228.          *    margin from our current position in the line.  If
  4229.          *    we are in a PRE block, start a new line if the last
  4230.          *    line already is within 6 characters of the wrap point
  4231.          *    for PRE blocks. - FM
  4232.          */
  4233.         if (me->sp[0].tag_number != HTML_PRE && !me->inPRE &&
  4234.         me->sp->style->freeFormat) {
  4235.         HTML_put_character(me, ' ');
  4236.         me->in_word = NO;
  4237.         } else if (HText_LastLineSize(me->text, FALSE) > (LYcols - 7)) {
  4238.         HTML_put_character(me, '\n');
  4239.         me->in_word = NO;
  4240.         }
  4241.  
  4242.         /*
  4243.          *    Get the TYPE and make sure we can handle it. - FM
  4244.          */
  4245.         if (present && present[HTML_INPUT_TYPE] &&
  4246.         value[HTML_INPUT_TYPE] && *value[HTML_INPUT_TYPE]) {
  4247.         I.type = value[HTML_INPUT_TYPE];
  4248.  
  4249.         if (!strcasecomp(I.type, "range")) {
  4250.             if (present[HTML_INPUT_MIN])
  4251.             I.min = value[HTML_INPUT_MIN];
  4252.             if (present[HTML_INPUT_MAX])
  4253.             I.max = value[HTML_INPUT_MAX];
  4254.             /*
  4255.              *    Not yet implemented.
  4256.              */
  4257.             HTML_put_string(me,"[RANGE Input] (Not yet implemented.)");
  4258. #ifdef NOTDEFINED
  4259.             if (me->inFORM)
  4260.             HText_DisableCurrentForm();
  4261. #endif /* NOTDEFINED */
  4262.             CTRACE(tfp, "HTML: Ignoring TYPE=\"range\"\n");
  4263.             break;
  4264.  
  4265.         } else if (!strcasecomp(I.type, "file")) {
  4266.             if (present[HTML_INPUT_ACCEPT])
  4267.             I.accept = value[HTML_INPUT_ACCEPT];
  4268.             /*
  4269.              *    Not yet implemented.
  4270.              */
  4271.             if (me->inUnderline == FALSE) {
  4272.             HText_appendCharacter(me->text,
  4273.                           LY_UNDERLINE_START_CHAR);
  4274.             }
  4275.             HTML_put_string(me,"[FILE Input] (Not yet implemented.)");
  4276.             if (me->inUnderline == FALSE) {
  4277.             HText_appendCharacter(me->text,
  4278.                           LY_UNDERLINE_END_CHAR);
  4279.             }
  4280. #ifdef NOTDEFINED
  4281.             if (me->inFORM)
  4282.             HText_DisableCurrentForm();
  4283. #endif /* NOTDEFINED */
  4284.             CTRACE(tfp, "HTML: Ignoring TYPE=\"file\"\n");
  4285.             break;
  4286.  
  4287.         } else if (!strcasecomp(I.type, "button")) {
  4288.             /*
  4289.              *    Ugh, a button for a script.
  4290.              */
  4291.             HTML_put_string(me,"[BUTTON] ");
  4292.             break;
  4293.         }
  4294.         }
  4295.  
  4296.         /*
  4297.          *    Check if we're in a form. - FM
  4298.          */
  4299.         if (!me->inFORM) {
  4300.         if (TRACE) {
  4301.             fprintf(tfp,
  4302.                 "Bad HTML: INPUT tag not within FORM tag\n");
  4303.         } else if (!me->inBadHTML) {
  4304.             _statusline(BAD_HTML_USE_TRACE);
  4305.             me->inBadHTML = TRUE;
  4306.             sleep(MessageSecs);
  4307.         }
  4308.         /*
  4309.          *  We'll process it, since the chances of a crash are
  4310.          *  small, and we probably do have a form started. - FM
  4311.          *
  4312.         break;
  4313.          */
  4314.         }
  4315.  
  4316.         /*
  4317.          *    Check for an unclosed TEXTAREA.
  4318.          */
  4319.         if (me->inTEXTAREA) {
  4320.         if (TRACE) {
  4321.             fprintf(tfp,
  4322.                 "Bad HTML: Missing TEXTAREA end tag.\n");
  4323.         } else if (!me->inBadHTML) {
  4324.             _statusline(BAD_HTML_USE_TRACE);
  4325.             me->inBadHTML = TRUE;
  4326.             sleep(MessageSecs);
  4327.         }
  4328.         }
  4329.  
  4330.         /*
  4331.          *    Check for an unclosed SELECT, try to close it if found.
  4332.          */
  4333.         if (me->inSELECT) {
  4334.         CTRACE(tfp, "HTML: Missing SELECT end tag, faking it...\n");
  4335.         if (me->sp->tag_number != HTML_SELECT) {
  4336.             SET_SKIP_STACK(HTML_SELECT);
  4337.         }
  4338.         HTML_end_element(me, HTML_SELECT, (char **)&include);
  4339.         }
  4340.  
  4341.         /*
  4342.          *    Handle the INPUT as for a FORM. - FM
  4343.          */
  4344.         if (!(present && present[HTML_INPUT_NAME] &&
  4345.           value[HTML_INPUT_NAME])) {
  4346.         I.name = "";
  4347.         } else if (strchr(value[HTML_INPUT_NAME], '&') == NULL) {
  4348.         I.name = value[HTML_INPUT_NAME];
  4349.         } else {
  4350.         StrAllocCopy(I_name, value[HTML_INPUT_NAME]);
  4351.         UNESCAPE_FIELDNAME_TO_STD(&I_name);
  4352.         I.name = I_name;
  4353.         }
  4354.         if ((present && present[HTML_INPUT_ALT] &&
  4355.          value[HTML_INPUT_ALT] && *value[HTML_INPUT_ALT] &&
  4356.          I.type && !strcasecomp(I.type, "image")) &&
  4357.         !(present && present[HTML_INPUT_VALUE] &&
  4358.           value[HTML_INPUT_VALUE] && *value[HTML_INPUT_VALUE])) {
  4359.         /*
  4360.          *  This is a TYPE="image" using an ALT rather than
  4361.          *  VALUE attribute to indicate the link string for
  4362.          *  text clients or GUIs with image loading off, so
  4363.          *  set the flag to use that as if it were a VALUE
  4364.          *  attribute. - FM
  4365.          */
  4366.         UseALTasVALUE = TRUE;
  4367.         }
  4368.         if (clickable_images == TRUE &&
  4369.         present && present[HTML_INPUT_SRC] &&
  4370.         value[HTML_INPUT_SRC] && *value[HTML_INPUT_SRC] &&
  4371.         I.type && !strcasecomp(I.type, "image")) {
  4372.         StrAllocCopy(href, value[HTML_INPUT_SRC]);
  4373.         /*
  4374.          *  We have a TYPE="image" with a non-zero-length SRC
  4375.          *  attribute and want clickable images.  Make the
  4376.          *  SRC's value a link if it's still not zero-length
  4377.          *  legitiimizing it. - FM
  4378.          */
  4379.         url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
  4380.         if (*href) {
  4381.             /*
  4382.              *    Check whether a base tag is in effect. - FM
  4383.              */
  4384.             if ((me->inBASE && *href != '#') &&
  4385.             (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
  4386.             *temp != '\0')
  4387.             /*
  4388.              *  Use reference related to the base.
  4389.              */
  4390.             StrAllocCopy(href, temp);
  4391.             FREE(temp);
  4392.  
  4393.             /*
  4394.              *    Check whether to fill in localhost. - FM
  4395.              */
  4396.             LYFillLocalFileURL((char **)&href,
  4397.                        ((*href != '#' &&
  4398.                      me->inBASE) ?
  4399.                        me->base_href :
  4400.                        me->node_anchor->address));
  4401.  
  4402.             if (me->inA) {
  4403.             SET_SKIP_STACK(HTML_A);
  4404.             HTML_end_element(me, HTML_A, (char **)&include);
  4405.             }
  4406.             me->CurrentA = HTAnchor_findChildAndLink(
  4407.                     me->node_anchor,    /* Parent */
  4408.                     NULL,            /* Tag */
  4409.                     href,            /* Addresss */
  4410.                     (HTLinkType*)0);    /* Type */
  4411.             HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
  4412.             if (me->inBoldH == FALSE)
  4413.             HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  4414.             HTML_put_string(me, VERBOSE_IMG(value, "[IMAGE]"));
  4415.             if (me->inBoldH == FALSE)
  4416.             HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  4417.             HText_endAnchor(me->text, 0);
  4418.             HTML_put_character(me, '-');
  4419.             HaveSRClink = TRUE;
  4420.         }
  4421.         FREE(href);
  4422.         }
  4423.         if ((UseALTasVALUE == TRUE) ||
  4424.         (present && present[HTML_INPUT_VALUE] &&
  4425.          value[HTML_INPUT_VALUE] && *value[HTML_INPUT_VALUE])) {
  4426.         /*
  4427.          *  Convert any HTML entities or decimal escaping. - FM
  4428.          */
  4429.         int CurrentCharSet = current_char_set;
  4430.         BOOL CurrentEightBitRaw = HTPassEightBitRaw;
  4431.         BOOLEAN CurrentUseDefaultRawMode = LYUseDefaultRawMode;
  4432.         HTCJKlang CurrentHTCJK = HTCJK;
  4433.         int len;
  4434.  
  4435.         if (I.type && !strcasecomp(I.type, "hidden")) {
  4436.             me->HiddenValue = TRUE;
  4437.             current_char_set = 0;    /* Default ISO-Latin1 */
  4438.             LYUseDefaultRawMode = TRUE;
  4439.             HTMLSetCharacterHandling(current_char_set);
  4440.         }
  4441.  
  4442.         if (!I.type)
  4443.             me->UsePlainSpace = TRUE;
  4444.         else if (!strcasecomp(I.type, "text") ||
  4445.              !strcasecomp(I.type, "submit") ||
  4446.              !strcasecomp(I.type, "image") ||
  4447.              !strcasecomp(I.type, "reset"))
  4448.             me->UsePlainSpace = TRUE;
  4449.         StrAllocCopy(I_value,
  4450.                  ((UseALTasVALUE == TRUE) ?
  4451.                 value[HTML_INPUT_ALT] :
  4452.                 value[HTML_INPUT_VALUE]));
  4453.         if (me->UsePlainSpace && !me->HiddenValue) {
  4454.             I.value_cs = current_char_set;
  4455.         }
  4456.         TRANSLATE_AND_UNESCAPE_ENTITIES6(
  4457.             &I_value,
  4458.             ATTR_CS_IN,
  4459.             I.value_cs,
  4460.             (me->UsePlainSpace && !me->HiddenValue),
  4461.             me->UsePlainSpace, me->HiddenValue);
  4462.         I.value = I_value;
  4463.         if (me->UsePlainSpace == TRUE) {
  4464.             /*
  4465.              *    Convert any newlines or tabs to spaces,
  4466.              *    and trim any lead or trailing spaces. - FM
  4467.              */
  4468.             convert_to_spaces(I.value, FALSE);
  4469.             while (I.value && I.value[0] == ' ')
  4470.             I.value++;
  4471.             len = strlen(I.value) - 1;
  4472.             while (len > 0 && I.value[len] == ' ')
  4473.             I.value[len--] = '\0';
  4474.         }
  4475.         me->UsePlainSpace = FALSE;
  4476.  
  4477.  
  4478.         if (I.type && !strcasecomp(I.type, "hidden")) {
  4479.             me->HiddenValue = FALSE;
  4480.             current_char_set = CurrentCharSet;
  4481.             LYUseDefaultRawMode = CurrentUseDefaultRawMode;
  4482.             HTMLSetCharacterHandling(current_char_set);
  4483.             HTPassEightBitRaw = CurrentEightBitRaw;
  4484.             HTCJK = CurrentHTCJK;
  4485.         }
  4486.         } else if (HaveSRClink == TRUE) {
  4487.         /*
  4488.          *  We put up an [IMAGE] link and '-' for a TYPE="image"
  4489.          *  and didn't get a VALUE or ALT string, so fake a
  4490.          *  "Submit" value.  If we didn't put up a link, then
  4491.          *  HText_beginInput() will use "[IMAGE]-Submit". - FM
  4492.          */
  4493.         StrAllocCopy(I_value, "Submit");
  4494.         I.value = I_value;
  4495.         }
  4496.         if (present && present[HTML_INPUT_CHECKED])
  4497.         I.checked = YES;
  4498.         if (present && present[HTML_INPUT_SIZE] &&
  4499.         value[HTML_INPUT_SIZE] && *value[HTML_INPUT_SIZE])
  4500.         I.size = value[HTML_INPUT_SIZE];
  4501.         if (present && present[HTML_INPUT_MAXLENGTH] &&
  4502.         value[HTML_INPUT_MAXLENGTH] && *value[HTML_INPUT_MAXLENGTH])
  4503.         I.maxlength = value[HTML_INPUT_MAXLENGTH];
  4504.         if (present && present[HTML_INPUT_DISABLED])
  4505.         I.disabled = YES;
  4506.  
  4507.         if (present && present[HTML_INPUT_ACCEPT_CHARSET]) { /* Not yet used. */
  4508.         I.accept_cs = value[HTML_INPUT_ACCEPT_CHARSET] ?
  4509.                   value[HTML_INPUT_ACCEPT_CHARSET] : "UNKNOWN";
  4510.         }
  4511.         if (present && present[HTML_INPUT_ALIGN] && /* Not yet used. */
  4512.         value[HTML_INPUT_ALIGN] && *value[HTML_INPUT_ALIGN])
  4513.         I.align = value[HTML_INPUT_ALIGN];
  4514.         if (present && present[HTML_INPUT_CLASS] && /* Not yet used. */
  4515.         value[HTML_INPUT_CLASS] && *value[HTML_INPUT_CLASS])
  4516.         I.class = value[HTML_INPUT_CLASS];
  4517.         if (present && present[HTML_INPUT_ERROR] && /* Not yet used. */
  4518.         value[HTML_INPUT_ERROR] && *value[HTML_INPUT_ERROR])
  4519.         I.error = value[HTML_INPUT_ERROR];
  4520.         if (present && present[HTML_INPUT_HEIGHT] && /* Not yet used. */
  4521.         value[HTML_INPUT_HEIGHT] && *value[HTML_INPUT_HEIGHT])
  4522.         I.height = value[HTML_INPUT_HEIGHT];
  4523.         if (present && present[HTML_INPUT_WIDTH] && /* Not yet used. */
  4524.         value[HTML_INPUT_WIDTH] && *value[HTML_INPUT_WIDTH])
  4525.         I.width = value[HTML_INPUT_WIDTH];
  4526.         if (present && present[HTML_INPUT_ID] &&
  4527.         value[HTML_INPUT_ID] && *value[HTML_INPUT_ID]) {
  4528.         I.id = value[HTML_INPUT_ID];
  4529.         CHECK_ID(HTML_INPUT_ID);
  4530.         }
  4531.         if (present && present[HTML_INPUT_LANG] && /* Not yet used. */
  4532.         value[HTML_INPUT_LANG] && *value[HTML_INPUT_LANG])
  4533.         I.lang = value[HTML_INPUT_LANG];
  4534.         if (present && present[HTML_INPUT_MD] && /* Not yet used. */
  4535.         value[HTML_INPUT_MD] && *value[HTML_INPUT_MD])
  4536.         I.md = value[HTML_INPUT_MD];
  4537.  
  4538.         chars = HText_beginInput(me->text, me->inUnderline, &I);
  4539.         /*
  4540.          *    Submit and reset buttons have values which don't change,
  4541.          *    so HText_beginInput() sets I.value to the string which
  4542.          *    should be displayed, and we'll enter that instead of
  4543.          *    underscore placeholders into the HText structure to
  4544.          *    see it instead of underscores when dumping or printing.
  4545.          *    We also won't worry about a wrap in PRE blocks, because
  4546.          *    the line editor never is invoked for submit or reset
  4547.          *    buttons. - LE & FM
  4548.          */
  4549.         if (I.type &&
  4550.         (!strcasecomp(I.type,"submit") ||
  4551.          !strcasecomp(I.type,"reset") ||
  4552.          !strcasecomp(I.type,"image")))
  4553.         IsSubmitOrReset = TRUE;
  4554.  
  4555.         if (I.type && chars == 3 &&
  4556.         !strcasecomp(I.type, "radio")) {
  4557.         /*
  4558.          *  Put a (_) placeholder, and one space
  4559.          *  (collapsible) before the label that is
  4560.          *  expected to follow. - FM
  4561.          */
  4562.         HTML_put_string(me, "(_)");
  4563.         chars = 0;
  4564.         me->in_word = YES;
  4565.         if (me->sp[0].tag_number != HTML_PRE &&
  4566.             me->sp->style->freeFormat) {
  4567.             HTML_put_character(me, ' ');
  4568.             me->in_word = NO;
  4569.         }
  4570.         } else if (I.type && chars == 3 &&
  4571.         !strcasecomp(I.type, "checkbox")) {
  4572.         /*
  4573.          *  Put a [_] placeholder, and one space
  4574.          *  (collapsible) before the label that is
  4575.          *  expected to follow. - FM
  4576.          */
  4577.         HTML_put_string(me, "[_]");
  4578.         chars = 0;
  4579.         me->in_word = YES;
  4580.         if (me->sp[0].tag_number != HTML_PRE &&
  4581.             me->sp->style->freeFormat) {
  4582.             HTML_put_character(me, ' ');
  4583.             me->in_word = NO;
  4584.         }
  4585.         } else if ((me->sp[0].tag_number == HTML_PRE ||
  4586.             !me->sp->style->freeFormat)
  4587.                && chars > 6 &&
  4588.                IsSubmitOrReset == FALSE) {
  4589.         /*
  4590.          *  This is not a submit or reset button, and we are
  4591.          *  in a PRE block with a field intended to exceed 6
  4592.          *  character widths.  The code inadequately handles
  4593.          *  INPUT fields in PRE tags if wraps occur (at the
  4594.          *  right margin) for the underscore placeholders.
  4595.          *  We'll put up a minimum of 6 underscores, since we
  4596.          *  should have wrapped artificially, above, if the
  4597.          *  INPUT begins within 6 columns of the right margin,
  4598.          *  and if any more would exceed the wrap column, we'll
  4599.          *  ignore them.  Note that if we somehow get tripped
  4600.          *  up and a wrap still does occur before all 6 of the
  4601.          *  underscores are output, the wrapped ones won't be
  4602.          *   treated as part of the editing window, nor be
  4603.          *  highlighted when not editing (Yuk!). - FM
  4604.          */
  4605.         for (i = 0; i < 6; i++) {
  4606.             HTML_put_character(me, '_');
  4607.             chars--;
  4608.         }
  4609.         HText_setIgnoreExcess(me->text, TRUE);
  4610.         }
  4611.         if (IsSubmitOrReset == FALSE) {
  4612.         /*
  4613.          *  This is not a submit or reset button,
  4614.          *  so output the rest of the underscore
  4615.          *  placeholders, if any more are needed. - FM
  4616.          */
  4617.         for (; chars > 0; chars--)
  4618.             HTML_put_character(me, '_');
  4619.         } else {
  4620.         if (me->sp[0].tag_number == HTML_PRE ||
  4621.             !me->sp->style->freeFormat) {
  4622.             /*
  4623.              *    We have a submit or reset button in a PRE block,
  4624.              *    so output the entire value from the markup.  If
  4625.              *    it extends to the right margin, it will wrap
  4626.              *    there, and only the portion before that wrap will
  4627.              *    be hightlighted on screen display (Yuk!) but we
  4628.              *    may as well show the rest of the full value on
  4629.              *    the next or more lines. - FM
  4630.              */
  4631.             while (I.value[i])
  4632.             HTML_put_character(me, I.value[i++]);
  4633.         } else {
  4634.             /*
  4635.              *    The submit or reset button is not in a PRE block.
  4636.              *    Note that if a wrap occurs before outputting the
  4637.              *    entire value, the wrapped portion will not be
  4638.              *    highlighted or clearly indicated as part of the
  4639.              *    link for submission or reset (Yuk!).
  4640.              *    We'll replace any spaces in the submit or reset
  4641.              *    button value with nbsp, to promote a wrap at the
  4642.              *    space we ensured would be present before the start
  4643.              *    of the string, as when we use all underscores
  4644.              *    instead of the INPUT's actual value, but we could
  4645.              *    still get a wrap at the right margin, instead, if
  4646.              *    the value is greater than a line width for the
  4647.              *    current style.    Also, if chars somehow ended up
  4648.              *    longer than the length of the actual value
  4649.              *    (shouldn't have), we'll continue padding with nbsp
  4650.              *    up to the length of chars. - FM
  4651.              */
  4652.             for (i = 0; I.value[i]; i++)
  4653.             HTML_put_character(me,
  4654.                        (I.value[i] ==  ' ' ?
  4655.                         HT_NON_BREAK_SPACE : I.value[i]));
  4656.             while (i < chars)
  4657.             HTML_put_character(me, HT_NON_BREAK_SPACE);
  4658.         }
  4659.         }
  4660.         HText_setIgnoreExcess(me->text, FALSE);
  4661.         FREE(I_value);
  4662.         FREE(I_name);
  4663.     }
  4664.     break;
  4665.  
  4666.     case HTML_TEXTAREA:
  4667.     /*
  4668.      *  Make sure we're in a form.
  4669.      */
  4670.     if (!me->inFORM) {
  4671.         if (TRACE) {
  4672.         fprintf(tfp,
  4673.             "Bad HTML: TEXTAREA start tag not within FORM tag\n");
  4674.         } else if (!me->inBadHTML) {
  4675.         _statusline(BAD_HTML_USE_TRACE);
  4676.         me->inBadHTML = TRUE;
  4677.         sleep(MessageSecs);
  4678.         }
  4679.         /*
  4680.          *    Too likely to cause a crash, so we'll ignore it. - FM
  4681.          */
  4682.         break;
  4683.     }
  4684.  
  4685.     /*
  4686.      *  Set to know we are in a textarea.
  4687.      */
  4688.     me->inTEXTAREA = TRUE;
  4689.  
  4690.     /*
  4691.      *  Get ready for the value.
  4692.      */
  4693.     HTChunkClear(&me->textarea);
  4694.     if (present && present[HTML_TEXTAREA_NAME] &&
  4695.         value[HTML_TEXTAREA_NAME]) {
  4696.         StrAllocCopy(me->textarea_name, value[HTML_TEXTAREA_NAME]);
  4697.         me->textarea_name_cs = ATTR_CS_IN;
  4698.         if (strchr(value[HTML_TEXTAREA_NAME], '&') != NULL) {
  4699.         UNESCAPE_FIELDNAME_TO_STD(&me->textarea_name);
  4700.         }
  4701.     } else {
  4702.         StrAllocCopy(me->textarea_name, "");
  4703.     }
  4704.  
  4705.     if (present && present[HTML_TEXTAREA_ACCEPT_CHARSET]) {
  4706.         if (value[HTML_TEXTAREA_ACCEPT_CHARSET]) {
  4707.         StrAllocCopy(me->textarea_accept_cs, value[HTML_TEXTAREA_ACCEPT_CHARSET]);
  4708.         TRANSLATE_AND_UNESCAPE_TO_STD(&me->textarea_accept_cs);
  4709.         } else {
  4710.         StrAllocCopy(me->textarea_accept_cs, "UNKNOWN");
  4711.         }
  4712.     } else {
  4713.         FREE(me->textarea_accept_cs);
  4714.     }
  4715.  
  4716.     if (present && present[HTML_TEXTAREA_COLS] &&
  4717.         value[HTML_TEXTAREA_COLS] &&
  4718.         isdigit((unsigned char)*value[HTML_TEXTAREA_COLS]))
  4719.         StrAllocCopy(me->textarea_cols, value[HTML_TEXTAREA_COLS]);
  4720.     else
  4721.         StrAllocCopy(me->textarea_cols, "60");
  4722.  
  4723.     if (present && present[HTML_TEXTAREA_ROWS] &&
  4724.         value[HTML_TEXTAREA_ROWS] &&
  4725.         isdigit((unsigned char)*value[HTML_TEXTAREA_ROWS]))
  4726.         me->textarea_rows = atoi(value[HTML_TEXTAREA_ROWS]);
  4727.     else
  4728.         me->textarea_rows = 4;
  4729.  
  4730.     if (present && present[HTML_TEXTAREA_DISABLED])
  4731.         me->textarea_disabled = YES;
  4732.     else
  4733.         me->textarea_disabled = NO;
  4734.  
  4735.     if (present && present[HTML_TEXTAREA_ID]
  4736.         && value[HTML_TEXTAREA_ID] && *value[HTML_TEXTAREA_ID]) {
  4737.         StrAllocCopy(id_string, value[HTML_TEXTAREA_ID]);
  4738.         TRANSLATE_AND_UNESCAPE_TO_STD(&id_string);
  4739.         if ((id_string != '\0') &&
  4740.         (ID_A = HTAnchor_findChildAndLink(
  4741.                 me->node_anchor,    /* Parent */
  4742.                 id_string,        /* Tag */
  4743.                 NULL,            /* Addresss */
  4744.                 (HTLinkType*)0))) {    /* Type */
  4745.         HText_beginAnchor(me->text, me->inUnderline, ID_A);
  4746.         HText_endAnchor(me->text, 0);
  4747.         StrAllocCopy(me->textarea_id, id_string);
  4748.         } else {
  4749.         FREE(me->textarea_id);
  4750.         }
  4751.         FREE(id_string);
  4752.     } else {
  4753.         FREE(me->textarea_id);
  4754.     }
  4755.     break;
  4756.  
  4757.     case HTML_SELECT:
  4758.     /*
  4759.      *  Check for an already open SELECT block. - FM
  4760.      */
  4761.     if (me->inSELECT) {
  4762.         if (TRACE) {
  4763.         fprintf(tfp,
  4764.            "Bad HTML: SELECT start tag in SELECT element. Faking SELECT end tag. *****\n");
  4765.         } else if (!me->inBadHTML) {
  4766.         _statusline(BAD_HTML_USE_TRACE);
  4767.         me->inBadHTML = TRUE;
  4768.         sleep(MessageSecs);
  4769.         }
  4770.         if (me->sp->tag_number != HTML_SELECT) {
  4771.         SET_SKIP_STACK(HTML_SELECT);
  4772.         }
  4773.         HTML_end_element(me, HTML_SELECT, (char **)&include);
  4774.     }
  4775.  
  4776.     /*
  4777.      * Start a new SELECT block. - FM
  4778.      */
  4779.     LYHandleSELECT(me,
  4780.                present, (CONST char **)value,
  4781.                (char **)&include,
  4782.                TRUE);
  4783.     break;
  4784.  
  4785.     case HTML_OPTION:
  4786.     {
  4787.         /*
  4788.          *    An option is a special case of an input field.
  4789.          */
  4790.         InputFieldData I;
  4791.  
  4792.         /*
  4793.          *    Make sure we're in a select tag.
  4794.          */
  4795.         if (!me->inSELECT) {
  4796.         if (TRACE) {
  4797.             fprintf(tfp,
  4798.                 "Bad HTML: OPTION tag not within SELECT tag\n");
  4799.         } else if (!me->inBadHTML) {
  4800.             _statusline(BAD_HTML_USE_TRACE);
  4801.             me->inBadHTML = TRUE;
  4802.             sleep(MessageSecs);
  4803.         }
  4804.  
  4805.         /*
  4806.          *  Too likely to cause a crash, so we'll ignore it. - FM
  4807.          */
  4808.         break;
  4809.         }
  4810.  
  4811.         if (!me->first_option) {
  4812.         /*
  4813.          *  Finish the data off.
  4814.          */
  4815.         HTChunkTerminate(&me->option);
  4816.  
  4817.         /*
  4818.          *  Finish the previous option @@@@@
  4819.          */
  4820.         HText_setLastOptionValue(me->text,
  4821.                      me->option.data,
  4822.                      me->LastOptionValue,
  4823.                      MIDDLE_ORDER,
  4824.                      me->LastOptionChecked,
  4825.                      me->UCLYhndl,
  4826.                      ATTR_CS_IN);
  4827.         }
  4828.  
  4829.         /*
  4830.          *    If its not a multiple option list and select popups
  4831.          *    are enabled, then don't use the checkbox/button method,
  4832.          *    and don't put anything on the screen yet.
  4833.          */
  4834.         if (me->first_option ||
  4835.         HTCurSelectGroupType == F_CHECKBOX_TYPE ||
  4836.         LYSelectPopups == FALSE) {
  4837.         if (HTCurSelectGroupType == F_CHECKBOX_TYPE ||
  4838.             LYSelectPopups == FALSE) {
  4839.             /*
  4840.              *    Start a newline before each option.
  4841.              */
  4842.             LYEnsureSingleSpace(me);
  4843.         } else {
  4844.             /*
  4845.              *    Add option list designation character.
  4846.              */
  4847.             HText_appendCharacter(me->text, '[');
  4848.             me->in_word = YES;
  4849.         }
  4850.  
  4851.         /*
  4852.          *  Inititialize.
  4853.          */
  4854.         I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL;
  4855.         I.disabled=NO; I.error=NULL; I.height= NULL; I.id=NULL;
  4856.         I.lang=NULL; I.max=NULL; I.maxlength=NULL; I.md=NULL;
  4857.         I.min=NULL; I.name=NULL; I.size=NULL; I.src=NULL;
  4858.         I.type=NULL; I.value=NULL; I.width=NULL;
  4859.         I.accept_cs = NULL;
  4860.         I.name_cs = -1;
  4861.         I.value_cs = current_char_set;
  4862.  
  4863.         I.type = "OPTION";
  4864.  
  4865.         if ((present && present[HTML_OPTION_SELECTED]) ||
  4866.             (me->first_option && LYSelectPopups == FALSE &&
  4867.              HTCurSelectGroupType == F_RADIO_TYPE))
  4868.             I.checked=YES;
  4869.  
  4870.         if (present && present[HTML_OPTION_VALUE] &&
  4871.             value[HTML_OPTION_VALUE]) {
  4872.             /*
  4873.              *    Convert any HTML entities or decimal escaping. - FM
  4874.              */
  4875.             StrAllocCopy(I_value, value[HTML_OPTION_VALUE]);
  4876.             me->HiddenValue = TRUE;
  4877.             TRANSLATE_AND_UNESCAPE_ENTITIES6(&I_value,
  4878.                                ATTR_CS_IN,
  4879.                                ATTR_CS_IN,
  4880.                             NO,
  4881.                                me->UsePlainSpace, me->HiddenValue);
  4882.             I.value_cs = ATTR_CS_IN;
  4883.             me->HiddenValue = FALSE;
  4884.  
  4885.             I.value = I_value;
  4886.         }
  4887.  
  4888.         if (me->select_disabled ||
  4889.            (present && present[HTML_OPTION_DISABLED]))
  4890.             I.disabled=YES;
  4891.  
  4892.         if (present && present[HTML_OPTION_ID]
  4893.             && value[HTML_OPTION_ID] && *value[HTML_OPTION_ID]) {
  4894.             if ((ID_A = HTAnchor_findChildAndLink(
  4895.                     me->node_anchor,       /* Parent */
  4896.                     value[HTML_OPTION_ID], /* Tag */
  4897.                     NULL,           /* Addresss */
  4898.                     (HTLinkType*)0)) != NULL) {    /* Type */
  4899.             HText_beginAnchor(me->text, me->inUnderline, ID_A);
  4900.             HText_endAnchor(me->text, 0);
  4901.             I.id = value[HTML_OPTION_ID];
  4902.             }
  4903.         }
  4904.  
  4905.         HText_beginInput(me->text, me->inUnderline, &I);
  4906.  
  4907.         if (HTCurSelectGroupType == F_CHECKBOX_TYPE) {
  4908.             /*
  4909.              *    Put a "[_]" placeholder, and one space
  4910.              *    (collapsible) before the label that is
  4911.              *    expected to follow. - FM
  4912.              */
  4913.             HText_appendCharacter(me->text, '[');
  4914.             HText_appendCharacter(me->text, '_');
  4915.             HText_appendCharacter(me->text, ']');
  4916.             HText_appendCharacter(me->text, ' ');
  4917.             HText_setLastChar(me->text, ' ');  /* absorb white space */
  4918.             me->in_word = NO;
  4919.         } else if (LYSelectPopups == FALSE) {
  4920.             /*
  4921.              *    Put a "(_)" placeholder, and one space
  4922.              *    (collapsible) before the label that is
  4923.              *    expected to follow. - FM
  4924.              */
  4925.             HText_appendCharacter(me->text, '(');
  4926.             HText_appendCharacter(me->text, '_');
  4927.             HText_appendCharacter(me->text, ')');
  4928.             HText_appendCharacter(me->text, ' ');
  4929.             HText_setLastChar(me->text, ' ');  /* absorb white space */
  4930.             me->in_word = NO;
  4931.         }
  4932.         }
  4933.  
  4934.         /*
  4935.          *    Get ready for the next value.
  4936.          */
  4937.         HTChunkClear(&me->option);
  4938.         if ((present && present[HTML_OPTION_SELECTED]) ||
  4939.         (me->first_option && LYSelectPopups == FALSE &&
  4940.          HTCurSelectGroupType == F_RADIO_TYPE))
  4941.         me->LastOptionChecked = TRUE;
  4942.         else
  4943.         me->LastOptionChecked = FALSE;
  4944.         me->first_option = FALSE;
  4945.  
  4946.  
  4947.         if (present && present[HTML_OPTION_VALUE] &&
  4948.         value[HTML_OPTION_VALUE]) {
  4949.         if (!I_value) {
  4950.             /*
  4951.              *    Convert any HTML entities or decimal escaping. - FM
  4952.              */
  4953.             StrAllocCopy(I_value, value[HTML_OPTION_VALUE]);
  4954.             me->HiddenValue = TRUE;
  4955.             TRANSLATE_AND_UNESCAPE_ENTITIES6(&I_value,
  4956.                                ATTR_CS_IN,
  4957.                                ATTR_CS_IN,
  4958.                             NO,
  4959.                                me->UsePlainSpace, me->HiddenValue);
  4960.             me->HiddenValue = FALSE;
  4961.         }
  4962.         StrAllocCopy(me->LastOptionValue, I_value);
  4963.         } else {
  4964.         StrAllocCopy(me->LastOptionValue, me->option.data);
  4965.         }
  4966.  
  4967.         /*
  4968.          *    If this is a popup option, print its option
  4969.          *    for use in selecting option by number. - LE
  4970.          */
  4971.         if (HTCurSelectGroupType == F_RADIO_TYPE &&
  4972.         LYSelectPopups &&
  4973.         keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
  4974.         char marker[8];
  4975.         int opnum = HText_getOptionNum(me->text);
  4976.  
  4977.         if (opnum > 0 && opnum < 100000) {
  4978.             sprintf(marker,"(%d)", opnum);
  4979.             HTML_put_string(me, marker);
  4980.             for (i = strlen(marker); i < 5; ++i) {
  4981.             HTML_put_character(me, '_');
  4982.             }
  4983.         }
  4984.         }
  4985.         FREE(I_value);
  4986.     }
  4987.     break;
  4988.  
  4989.     case HTML_TABLE:
  4990.     /*
  4991.      *  Not implemented.  Just treat as a division
  4992.      *  with respect to any ALIGN attribute, with
  4993.      *  a default of HT_LEFT, or leave as a PRE
  4994.      *  block if we are presently in one. - FM
  4995.      */
  4996.     if (me->inA) {
  4997.         SET_SKIP_STACK(HTML_A);
  4998.         HTML_end_element(me, HTML_A, (char **)&include);
  4999.     }
  5000.     if (me->Underline_Level > 0) {
  5001.         SET_SKIP_STACK(HTML_U);
  5002.         HTML_end_element(me, HTML_U, (char **)&include);
  5003.     }
  5004.     me->inTABLE = TRUE;
  5005.     if (!strcmp(me->sp->style->name, "Preformatted")) {
  5006.         UPDATE_STYLE;
  5007.         CHECK_ID(HTML_TABLE_ID);
  5008.         break;
  5009.     }
  5010.     if (me->Division_Level < (MAX_NESTING - 1)) {
  5011.         me->Division_Level++;
  5012.     } else {
  5013.         CTRACE(tfp,
  5014.         "HTML: ****** Maximum nesting of %d divisions/tables exceeded!\n",
  5015.             MAX_NESTING);
  5016.     }
  5017.     if (present && present[HTML_TABLE_ALIGN] &&
  5018.         value[HTML_TABLE_ALIGN] && *value[HTML_TABLE_ALIGN]) {
  5019.         if (!strcasecomp(value[HTML_TABLE_ALIGN], "center")) {
  5020.         me->DivisionAlignments[me->Division_Level] = HT_CENTER;
  5021.         change_paragraph_style(me, styles[HTML_DCENTER]);
  5022.         UPDATE_STYLE;
  5023.         me->current_default_alignment = styles[HTML_DCENTER]->alignment;
  5024.         } else if (!strcasecomp(value[HTML_TABLE_ALIGN], "right")) {
  5025.         me->DivisionAlignments[me->Division_Level] = HT_RIGHT;
  5026.         change_paragraph_style(me, styles[HTML_DRIGHT]);
  5027.         UPDATE_STYLE;
  5028.         me->current_default_alignment = styles[HTML_DRIGHT]->alignment;
  5029.         } else {
  5030.         me->DivisionAlignments[me->Division_Level] = HT_LEFT;
  5031.         change_paragraph_style(me, styles[HTML_DLEFT]);
  5032.         UPDATE_STYLE;
  5033.         me->current_default_alignment = styles[HTML_DLEFT]->alignment;
  5034.         }
  5035.     } else {
  5036.         me->DivisionAlignments[me->Division_Level] = HT_LEFT;
  5037.         change_paragraph_style(me, styles[HTML_DLEFT]);
  5038.         UPDATE_STYLE;
  5039.         me->current_default_alignment = styles[HTML_DLEFT]->alignment;
  5040.     }
  5041.     CHECK_ID(HTML_TABLE_ID);
  5042.     break;
  5043.  
  5044.     case HTML_TR:
  5045.     /*
  5046.      *  Not yet implemented.  Just start a new row,
  5047.      *  if needed, act on an ALIGN attribute if present,
  5048.      *  and check for an ID link. - FM
  5049.      */
  5050.     if (me->inA) {
  5051.         SET_SKIP_STACK(HTML_A);
  5052.         HTML_end_element(me, HTML_A, (char **)&include);
  5053.     }
  5054.     if (me->Underline_Level > 0) {
  5055.         SET_SKIP_STACK(HTML_U);
  5056.         HTML_end_element(me, HTML_U, (char **)&include);
  5057.     }
  5058.     UPDATE_STYLE;
  5059.     if (HText_LastLineSize(me->text, FALSE)) {
  5060.         HText_setLastChar(me->text, ' ');  /* absorb white space */
  5061.         HText_appendCharacter(me->text, '\r');
  5062.     }
  5063.     me->in_word = NO;
  5064.  
  5065.     if (!strcmp(me->sp->style->name, "Preformatted")) {
  5066.         CHECK_ID(HTML_TR_ID);
  5067.         me->inP = FALSE;
  5068.         break;
  5069.     }
  5070.     if (LYoverride_default_alignment(me)) {
  5071.         me->sp->style->alignment = styles[me->sp[0].tag_number]->alignment;
  5072.     } else if (me->List_Nesting_Level >= 0 ||
  5073.            ((me->Division_Level < 0) &&
  5074.             (!strcmp(me->sp->style->name, "Normal") ||
  5075.              !strcmp(me->sp->style->name, "Preformatted")))) {
  5076.         me->sp->style->alignment = HT_LEFT;
  5077.     } else {
  5078.         me->sp->style->alignment = me->current_default_alignment;
  5079.     }
  5080.     if (present && present[HTML_TR_ALIGN] && value[HTML_TR_ALIGN]) {
  5081.         if (!strcasecomp(value[HTML_TR_ALIGN], "center") &&
  5082.         !(me->List_Nesting_Level >= 0 && !me->inP))
  5083.         me->sp->style->alignment = HT_CENTER;
  5084.         else if (!strcasecomp(value[HTML_TR_ALIGN], "right") &&
  5085.         !(me->List_Nesting_Level >= 0 && !me->inP))
  5086.         me->sp->style->alignment = HT_RIGHT;
  5087.         else if (!strcasecomp(value[HTML_TR_ALIGN], "left") ||
  5088.              !strcasecomp(value[HTML_TR_ALIGN], "justify"))
  5089.         me->sp->style->alignment = HT_LEFT;
  5090.     }
  5091.  
  5092.     CHECK_ID(HTML_TR_ID);
  5093.     me->inP = FALSE;
  5094.     break;
  5095.  
  5096.     case HTML_THEAD:
  5097.     case HTML_TFOOT:
  5098.     case HTML_TBODY:
  5099.     /*
  5100.      *  Not yet implemented.  Just check for an ID link. - FM
  5101.      */
  5102.     if (me->inA) {
  5103.         SET_SKIP_STACK(HTML_A);
  5104.         HTML_end_element(me, HTML_A, (char **)&include);
  5105.     }
  5106.     if (me->Underline_Level > 0) {
  5107.         SET_SKIP_STACK(HTML_U);
  5108.         HTML_end_element(me, HTML_U, (char **)&include);
  5109.     }
  5110.     UPDATE_STYLE;
  5111.     CHECK_ID(HTML_TR_ID);
  5112.     break;
  5113.  
  5114.     case HTML_COL:
  5115.     case HTML_COLGROUP:
  5116.     /*
  5117.      *  Not yet implemented.  Just check for an ID link. - FM
  5118.      */
  5119.     if (me->inA) {
  5120.         SET_SKIP_STACK(HTML_A);
  5121.         HTML_end_element(me, HTML_A, (char **)&include);
  5122.     }
  5123.     if (me->Underline_Level > 0) {
  5124.         SET_SKIP_STACK(HTML_U);
  5125.         HTML_end_element(me, HTML_U, (char **)&include);
  5126.     }
  5127.     UPDATE_STYLE;
  5128.     CHECK_ID(HTML_COL_ID);
  5129.     break;
  5130.  
  5131.     case HTML_TH:
  5132.     if (me->inA) {
  5133.         SET_SKIP_STACK(HTML_A);
  5134.         HTML_end_element(me, HTML_A, (char **)&include);
  5135.     }
  5136.     if (me->Underline_Level > 0) {
  5137.         SET_SKIP_STACK(HTML_U);
  5138.         HTML_end_element(me, HTML_U, (char **)&include);
  5139.     }
  5140.     UPDATE_STYLE;
  5141.     CHECK_ID(HTML_TD_ID);
  5142.     /*
  5143.      *  Not yet implemented.  Just add a collapsible space and break. - FM
  5144.      */
  5145.     HTML_put_character(me, ' ');
  5146.     me->in_word = NO;
  5147.     break;
  5148.  
  5149.     case HTML_TD:
  5150.     if (me->inA) {
  5151.         SET_SKIP_STACK(HTML_A);
  5152.         HTML_end_element(me, HTML_A, (char **)&include);
  5153.     }
  5154.     if (me->Underline_Level > 0) {
  5155.         SET_SKIP_STACK(HTML_U);
  5156.         HTML_end_element(me, HTML_U, (char **)&include);
  5157.     }
  5158.     UPDATE_STYLE;
  5159.     CHECK_ID(HTML_TD_ID);
  5160.     /*
  5161.      *  Not yet implemented.  Just add a collapsible space and break. - FM
  5162.      */
  5163.     HTML_put_character(me, ' ');
  5164.     me->in_word = NO;
  5165.     break;
  5166.  
  5167.     case HTML_MATH:
  5168.     /*
  5169.      *  We're getting it as Literal text, which, until we can process
  5170.      *  it, we'll display as is, within brackets to alert the user. - FM
  5171.      */
  5172.     HTChunkClear(&me->math);
  5173.     CHECK_ID(HTML_GEN_ID);
  5174.     break;
  5175.  
  5176.     default:
  5177.     break;
  5178.  
  5179.     } /* end switch */
  5180.  
  5181. #if defined(DICKEY_TEST)
  5182.     if (HTML_dtd.tags[ElementNumber].contents != SGML_EMPTY)
  5183. #endif
  5184.     {
  5185.     if (me->skip_stack > 0) {
  5186.         CTRACE(tfp, "HTML:begin_element: internal call (level %d), leaving on stack - %s\n",
  5187.             me->skip_stack, me->sp->style->name);
  5188.         me->skip_stack--;
  5189.         return;
  5190.     }
  5191.     if (me->sp == me->stack) {
  5192.         if (me->stack_overrun == FALSE) {
  5193.         if (TRACE) {
  5194.             fprintf(tfp,
  5195.             "HTML: ****** Maximum nesting of %d tags exceeded!\n",
  5196.             MAX_NESTING);
  5197.  
  5198.         } else {
  5199.             HTAlert(HTML_STACK_OVERRUN);
  5200.         }
  5201.         me->stack_overrun = TRUE;
  5202.         }
  5203.         return;
  5204.     }
  5205.  
  5206.     CTRACE(tfp,"HTML:begin_element[%d]: adding style to stack - %s\n",
  5207.                                 STACKLEVEL(me),
  5208.                             me->new_style->name);
  5209.     (me->sp)--;
  5210.     me->sp[0].style = me->new_style;    /* Stack new style */
  5211.     me->sp[0].tag_number = ElementNumber;
  5212.     }
  5213.  
  5214. #if defined(DICKEY_TEST) && defined(USE_COLOR_STYLE)
  5215. /* end empty tags straight away */
  5216.     if (HTML_dtd.tags[ElementNumber].contents == SGML_EMPTY)
  5217.     {
  5218.         CTRACE(tfp, "STYLE:begin_element:ending EMPTY element style\n");
  5219. #if !defined(USE_HASH)
  5220.     HText_characterStyle(me->text, element_number+STARTAT, STACK_OFF);
  5221. #else
  5222.     HText_characterStyle(me->text, hcode, STACK_OFF);
  5223. #endif /* USE_HASH */
  5224.         {
  5225.             char *end, *start=NULL, *lookfrom;
  5226.             char tmp[64];
  5227.             sprintf(tmp, ";%s", HTML_dtd.tags[element_number].name);
  5228.             strtolower(tmp);
  5229.  
  5230.             lookfrom = Style_className;
  5231.             do
  5232.             {
  5233.                 end = start;
  5234.                 start = strstr(lookfrom, tmp);
  5235.                 if (start)
  5236.                     lookfrom = start + 1;
  5237.             }
  5238.             while (start);
  5239.             if (end)
  5240.                 *end='\0';
  5241.  
  5242. #if defined(PREVAIL)
  5243.             start=strrchr(Style_className, '.');
  5244.             if (start)
  5245.                 strcpy(prevailing_class, (char*)(start+1));
  5246.             else
  5247.                 strcpy(prevailing_class, "");
  5248. #endif
  5249.  
  5250.             CTRACE(tfp, "CSS:%s (trimmed %s, SGML_EMPTY)\n", Style_className, tmp);
  5251.         }
  5252.     }
  5253. #endif /* USE_COLOR_STYLE */
  5254. }
  5255.  
  5256. /*        End Element
  5257. **        -----------
  5258. **
  5259. **    When we end an element, the style must be returned to that
  5260. **    in effect before that element.    Note that anchors (etc?)
  5261. **    don't have an associated style, so that we must scan down the
  5262. **    stack for an element with a defined style. (In fact, the styles
  5263. **    should be linked to the whole stack not just the top one.)
  5264. **    TBL 921119
  5265. **
  5266. **    We don't turn on "CAREFUL" check because the parser produces
  5267. **    (internal code errors apart) good nesting. The parser checks
  5268. **    incoming code errors, not this module.
  5269. */
  5270. PRIVATE void HTML_end_element ARGS3(
  5271.     HTStructured *,     me,
  5272.     int,            element_number,
  5273.     char **,        include)
  5274. {
  5275.     int i = 0;
  5276.     char *temp = NULL, *cp = NULL;
  5277.     BOOL BreakFlag = FALSE;
  5278.  
  5279. #ifdef CAREFUL            /* parser assumed to produce good nesting */
  5280.     if (element_number != me->sp[0].tag_number &&
  5281.     HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
  5282.     CTRACE(tfp,
  5283.         "HTMLText: end of element %s when expecting end of %s\n",
  5284.         HTML_dtd.tags[element_number].name,
  5285.         HTML_dtd.tags[me->sp->tag_number].name);
  5286.         /* panic */
  5287.     }
  5288. #endif /* CAREFUL */
  5289.  
  5290.     /*
  5291.      *    If we're seeking MAPs, skip everything that's
  5292.      *    not a MAP or AREA tag. - FM
  5293.      */
  5294.     if (LYMapsOnly) {
  5295.     if (!(element_number == HTML_MAP || element_number == HTML_AREA)) {
  5296.         return;
  5297.     }
  5298.     }
  5299.  
  5300.     /*
  5301.      *    Pop state off stack if we didn't declare the element
  5302.      *    SGML_EMPTY in HTMLDTD.c. - FM & KW
  5303.      */
  5304.     if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
  5305.     if ((element_number != me->sp[0].tag_number) &&
  5306.         me->skip_stack <= 0 &&
  5307.         HTML_dtd.tags[HTML_LH].contents != SGML_EMPTY &&
  5308.         (me->sp[0].tag_number == HTML_UL ||
  5309.          me->sp[0].tag_number == HTML_OL ||
  5310.          me->sp[0].tag_number == HTML_MENU ||
  5311.          me->sp[0].tag_number == HTML_DIR) &&
  5312.         (element_number == HTML_H1 ||
  5313.          element_number == HTML_H2 ||
  5314.          element_number == HTML_H3 ||
  5315.          element_number == HTML_H4 ||
  5316.          element_number == HTML_H6 ||
  5317.          element_number == HTML_H6)) {
  5318.         /*
  5319.          *    Set the break flag if we're popping
  5320.          *    a dummy HTML_LH substituted for an
  5321.          *    HTML_H# encountered in a list.
  5322.          */
  5323.         BreakFlag = TRUE;
  5324.     }
  5325.     if (me->skip_stack > 0) {
  5326.          CTRACE(tfp, "HTML:end_element: Internal call (level %d), leaving on stack - %s\n",
  5327.             me->skip_stack, me->sp->style->name);
  5328.         me->skip_stack--;
  5329.     } else if (me->stack_overrun == TRUE &&
  5330.         element_number != me->sp[0].tag_number) {
  5331.         /*
  5332.          *    Ignore non-corresponding tags if we had
  5333.          *    a stack overrun.  This is not a completely
  5334.          *    fail-safe strategy for protection against
  5335.          *    any seriously adverse consequences of a
  5336.          *    stack overrun, and the rendering of the
  5337.          *    document will not be as intended, but we
  5338.          *    expect overruns to be rare, and this should
  5339.          *    offer reasonable protection against crashes
  5340.          *    if an overrun does occur. - FM
  5341.          */
  5342.         return;
  5343.     } else if (element_number == HTML_SELECT &&
  5344.         me->sp[0].tag_number != HTML_SELECT) {
  5345.         /*
  5346.          *    Ignore non-corresponding SELECT tags, since we
  5347.          *    probably popped it and closed the SELECT block
  5348.          *    to deal with markup which amounts to a nested
  5349.          *    SELECT, or an out of order FORM end tag. - FM
  5350.          */
  5351.         return;
  5352.     } else if ((element_number != me->sp[0].tag_number) &&
  5353.         HTML_dtd.tags[HTML_LH].contents == SGML_EMPTY &&
  5354.         (me->sp[0].tag_number == HTML_UL ||
  5355.          me->sp[0].tag_number == HTML_OL ||
  5356.          me->sp[0].tag_number == HTML_MENU ||
  5357.          me->sp[0].tag_number == HTML_DIR) &&
  5358.         (element_number == HTML_H1 ||
  5359.          element_number == HTML_H2 ||
  5360.          element_number == HTML_H3 ||
  5361.          element_number == HTML_H4 ||
  5362.          element_number == HTML_H6 ||
  5363.          element_number == HTML_H6)) {
  5364.         /*
  5365.          *    It's an H# for which we substituted
  5366.          *    an HTML_LH, which we've declared as
  5367.          *    SGML_EMPTY, so just return. - FM
  5368.          */
  5369.         return;
  5370.     } else if (me->sp < (me->stack + MAX_NESTING - 1)) {
  5371.         (me->sp)++;
  5372.         CTRACE(tfp, "HTML:end_element[%d]: Popped style off stack - %s\n",
  5373.                 STACKLEVEL(me),
  5374.             me->sp->style->name);
  5375.     } else {
  5376.         CTRACE(tfp,
  5377.   "Stack underflow error!  Tried to pop off more styles than exist in stack\n");
  5378.     }
  5379.     }
  5380.     if (BreakFlag == TRUE)
  5381.     return;
  5382.  
  5383.     /*
  5384.      *    Check for unclosed TEXTAREA. - FM
  5385.      */
  5386.     if (me->inTEXTAREA && element_number != HTML_TEXTAREA) {
  5387.     if (TRACE) {
  5388.         fprintf(tfp, "Bad HTML: Missing TEXTAREA end tag\n");
  5389.     } else if (!me->inBadHTML) {
  5390.         _statusline(BAD_HTML_USE_TRACE);
  5391.         me->inBadHTML = TRUE;
  5392.         sleep(MessageSecs);
  5393.     }
  5394.     }
  5395.  
  5396.     if (!me->text && !LYMapsOnly) {
  5397.     UPDATE_STYLE;
  5398.     }
  5399.  
  5400.     /*
  5401.      *    Handle the end tag. - FM
  5402.      */
  5403.     switch(element_number) {
  5404.  
  5405.     case HTML_HTML:
  5406.     if (me->inA || me->inSELECT || me->inTEXTAREA)
  5407.         if (TRACE) {
  5408.         fprintf(tfp,
  5409.             "Bad HTML: %s%s%s%s%s not closed before HTML end tag *****\n",
  5410.             me->inSELECT ? "SELECT" : "",
  5411.             (me->inSELECT && me->inTEXTAREA) ? ", " : "",
  5412.             me->inTEXTAREA ? "TEXTAREA" : "",
  5413.             ((me->inSELECT || me->inTEXTAREA) && me->inA) ? ", " : "",
  5414.             me->inA ? "A" : "");
  5415.         } else if (!me->inBadHTML) {
  5416.         _statusline(BAD_HTML_USE_TRACE);
  5417.         me->inBadHTML = TRUE;
  5418.         sleep(MessageSecs);
  5419.         }
  5420.     break;
  5421.  
  5422.     case HTML_HEAD:
  5423.     if (me->inBASE &&
  5424.         !strcmp(me->node_anchor->address, LYlist_temp_url())) {
  5425.         /*    If we are parsing the List Page, and have a BASE after
  5426.          *    we are done with the HEAD element, propagate it back
  5427.          *    to the node_anchor object.  The base should have been
  5428.          *    inserted by showlist() to record what document the List
  5429.          *    Page is about, and other functions may later look for it
  5430.          *    in the anchor. - kw
  5431.          */
  5432.         StrAllocCopy(me->node_anchor->content_base, me->base_href);
  5433.     }
  5434.     if (HText_hasToolbar(me->text))
  5435.         HText_appendParagraph(me->text);
  5436.     break;
  5437.  
  5438.     case HTML_TITLE:
  5439.     HTChunkTerminate(&me->title);
  5440.     HTAnchor_setTitle(me->node_anchor, me->title.data);
  5441.     HTChunkClear(&me->title);
  5442.     /*
  5443.      *  Check if it's a bookmark file, and if so, and multiple
  5444.      *  bookmark support is on, or it's off but this isn't the
  5445.      *  default bookmark file (e.g., because it was on before,
  5446.      *  and this is another bookmark file that has been retrieved
  5447.      *  as a previous document), insert the current description
  5448.      *  string and filepath for it.  We pass the strings back to
  5449.      *  the SGML parser so that any 8 bit or multibyte/CJK
  5450.      *  characters will be handled by the parser's state and
  5451.      *  charset routines. - FM
  5452.      */
  5453.     if (me->node_anchor->bookmark && *me->node_anchor->bookmark) {
  5454.         if ((LYMultiBookmarks == TRUE) ||
  5455.         ((bookmark_page && *bookmark_page) &&
  5456.          strcmp(me->node_anchor->bookmark, bookmark_page))) {
  5457.         for (i = 0; i <= MBM_V_MAXFILES; i++) {
  5458.             if (MBM_A_subbookmark[i] &&
  5459.             !strcmp(MBM_A_subbookmark[i],
  5460.                 me->node_anchor->bookmark)) {
  5461.             StrAllocCat(*include, "<H2><EM>Description:</EM> ");
  5462.             StrAllocCopy(temp,
  5463.                      ((MBM_A_subdescript[i] &&
  5464.                        *MBM_A_subdescript[i]) ?
  5465.                      MBM_A_subdescript[i] : "(none)"));
  5466.             LYEntify((char **)&temp, TRUE);
  5467.             StrAllocCat(*include, temp);
  5468.             StrAllocCat(*include,
  5469.                 "<BR><EM>   Filepath:</EM> ");
  5470.             StrAllocCopy(temp,
  5471.                      ((MBM_A_subbookmark[i] &&
  5472.                        *MBM_A_subbookmark[i]) ?
  5473.                      MBM_A_subbookmark[i] : "(unknown)"));
  5474.             LYEntify((char **)&temp, TRUE);
  5475.             StrAllocCat(*include, temp);
  5476.             FREE(temp);
  5477.             StrAllocCat(*include, "</H2>");
  5478.             break;
  5479.             }
  5480.         }
  5481.         }
  5482.     }
  5483.     break;
  5484.  
  5485.     case HTML_STYLE:
  5486.     /*
  5487.      *  We're getting it as Literal text, which, for now,
  5488.      *  we'll just ignore. - FM
  5489.      */
  5490.     HTChunkTerminate(&me->style_block);
  5491.     CTRACE(tfp, "HTML: STYLE content =\n%s\n",
  5492.                 me->style_block.data);
  5493.     HTChunkClear(&me->style_block);
  5494.     break;
  5495.  
  5496.     case HTML_SCRIPT:
  5497.     /*
  5498.      *  We're getting it as Literal text, which, for now,
  5499.      *  we'll just ignore. - FM
  5500.      */
  5501.     HTChunkTerminate(&me->script);
  5502.     CTRACE(tfp, "HTML: SCRIPT content =\n%s\n",
  5503.                 me->script.data);
  5504.     HTChunkClear(&me->script);
  5505.     break;
  5506.  
  5507.     case HTML_BODY:
  5508.     if (me->inA || me->inSELECT || me->inTEXTAREA)
  5509.         if (TRACE) {
  5510.         fprintf(tfp,
  5511.             "Bad HTML: %s%s%s%s%s not closed before BODY end tag *****\n",
  5512.             me->inSELECT ? "SELECT" : "",
  5513.             (me->inSELECT && me->inTEXTAREA) ? ", " : "",
  5514.             me->inTEXTAREA ? "TEXTAREA" : "",
  5515.             ((me->inSELECT || me->inTEXTAREA) && me->inA) ? ", " : "",
  5516.             me->inA ? "A" : "");
  5517.         } else if (!me->inBadHTML) {
  5518.         _statusline(BAD_HTML_USE_TRACE);
  5519.         me->inBadHTML = TRUE;
  5520.         sleep(MessageSecs);
  5521.         }
  5522.     break;
  5523.  
  5524.     case HTML_FRAMESET:
  5525.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5526.     break;
  5527.  
  5528.     case HTML_NOFRAMES:
  5529.     case HTML_IFRAME:
  5530.     LYEnsureDoubleSpace(me);
  5531.     LYResetParagraphAlignment(me);
  5532.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5533.     break;
  5534.  
  5535.     case HTML_BANNER:
  5536.     case HTML_MARQUEE:
  5537.     case HTML_BLOCKQUOTE:
  5538.     case HTML_BQ:
  5539.     case HTML_ADDRESS:
  5540.         /*
  5541.          *  Set flag to know that style has ended.
  5542.          *  Fall through.
  5543.         i_prior_style = -1;
  5544.          */
  5545.     change_paragraph_style(me, me->sp->style);
  5546.     UPDATE_STYLE;
  5547.     if (me->sp->tag_number == element_number)
  5548.         LYEnsureDoubleSpace(me);
  5549.     if (me->List_Nesting_Level >= 0)
  5550.         HText_NegateLineOne(me->text);
  5551.     break;
  5552.  
  5553.     case HTML_CENTER:
  5554.     case HTML_DIV:
  5555.     if (me->Division_Level >= 0)
  5556.         me->Division_Level--;
  5557.     if (me->Division_Level >= 0)
  5558.         me->sp->style->alignment =
  5559.                 me->DivisionAlignments[me->Division_Level];
  5560.     change_paragraph_style(me, me->sp->style);
  5561.     UPDATE_STYLE;
  5562.     me->current_default_alignment = me->sp->style->alignment;
  5563.     if (me->List_Nesting_Level >= 0)
  5564.         HText_NegateLineOne(me->text);
  5565.     break;
  5566.  
  5567.     case HTML_H1:            /* header styles */
  5568.     case HTML_H2:
  5569.     case HTML_H3:
  5570.     case HTML_H4:
  5571.     case HTML_H5:
  5572.     case HTML_H6:
  5573.     if (me->Division_Level >= 0) {
  5574.         me->sp->style->alignment =
  5575.                 me->DivisionAlignments[me->Division_Level];
  5576.     } else if (!strcmp(me->sp->style->name, "HeadingCenter") ||
  5577.            !strcmp(me->sp->style->name, "Heading1")) {
  5578.         me->sp->style->alignment = HT_CENTER;
  5579.     } else if (!strcmp(me->sp->style->name, "HeadingRight")) {
  5580.         me->sp->style->alignment = HT_RIGHT;
  5581.     } else {
  5582.         me->sp->style->alignment = HT_LEFT;
  5583.     }
  5584.     change_paragraph_style(me, me->sp->style);
  5585.     UPDATE_STYLE;
  5586.     if (styles[element_number]->font & HT_BOLD) {
  5587.         if (me->inBoldA == FALSE && me->inBoldH == TRUE) {
  5588.         HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  5589.         }
  5590.         me->inBoldH = FALSE;
  5591.     }
  5592.     if (me->List_Nesting_Level >= 0)
  5593.         HText_NegateLineOne(me->text);
  5594.     if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
  5595.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  5596.         me->inUnderline = TRUE;
  5597.     }
  5598.     break;
  5599.  
  5600.     case HTML_P:
  5601.     LYHandleP(me,
  5602.          (CONST BOOL*)0, (CONST char **)0,
  5603.          (char **)&include,
  5604.          FALSE);
  5605.     break;
  5606.  
  5607.     case HTML_FONT:
  5608.     me->inFONT = FALSE;
  5609.     break;
  5610.  
  5611.     case HTML_B:            /* Physical character highlighting */
  5612.     case HTML_BLINK:
  5613.     case HTML_I:
  5614.     case HTML_U:
  5615.  
  5616.     case HTML_CITE:            /* Logical character highlighting */
  5617.     case HTML_EM:
  5618.     case HTML_STRONG:
  5619.     /*
  5620.      *  Ignore any emphasis end tags if the
  5621.      *  Underline_Level is not set. - FM
  5622.      */
  5623.     if (me->Underline_Level <= 0)
  5624.         break;
  5625.  
  5626.     /*
  5627.      *  Adjust the Underline level counter, and
  5628.      *  turn off underlining if appropriate. - FM
  5629.      */
  5630.     me->Underline_Level--;
  5631.     if (me->inUnderline && me->Underline_Level < 1) {
  5632.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  5633.         me->inUnderline = FALSE;
  5634.         CTRACE(tfp, "Ending underline\n");
  5635.     } else {
  5636.         CTRACE(tfp, "Underline Level is %d\n", me->Underline_Level);
  5637.     }
  5638.     break;
  5639.  
  5640.     case HTML_ABBREV:    /* Miscellaneous character containers */
  5641.     case HTML_ACRONYM:
  5642.     case HTML_AU:
  5643.     case HTML_AUTHOR:
  5644.     case HTML_BIG:
  5645.     case HTML_CODE:
  5646.     case HTML_DFN:
  5647.     case HTML_KBD:
  5648.     case HTML_SAMP:
  5649.     case HTML_SMALL:
  5650.     case HTML_SUB:
  5651.     case HTML_SUP:
  5652.     case HTML_TT:
  5653.     case HTML_VAR:
  5654.     break;
  5655.  
  5656.     case HTML_DEL:
  5657.     case HTML_S:
  5658.     case HTML_STRIKE:
  5659.     HTML_put_character(me, ' ');
  5660.     if (me->inUnderline == FALSE)
  5661.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  5662.     HTML_put_string(me, ":DEL]");
  5663.     if (me->inUnderline == FALSE)
  5664.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  5665.     HTML_put_character(me, ' ');
  5666.     me->in_word = NO;
  5667.     break;
  5668.  
  5669.     case HTML_INS:
  5670.     HTML_put_character(me, ' ');
  5671.     if (me->inUnderline == FALSE)
  5672.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  5673.     HTML_put_string(me, ":INS]");
  5674.     if (me->inUnderline == FALSE)
  5675.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  5676.     HTML_put_character(me, ' ');
  5677.     me->in_word = NO;
  5678.     break;
  5679.  
  5680.     case HTML_Q:
  5681.     if (me->Quote_Level > 0)
  5682.         me->Quote_Level--;
  5683.     /*
  5684.      *  Should check LANG and/or DIR attributes, and the
  5685.      *  me->node_anchor->charset and/or yet to be added
  5686.      *  structure elements, to determine whether we should
  5687.      *  use chevrons, but for now we'll always use double-
  5688.      *  or single-quotes. - FM
  5689.      */
  5690.     if (!(me->Quote_Level & 1))
  5691.         HTML_put_character(me, '"');
  5692.     else
  5693.         HTML_put_character(me, '\'');
  5694.     break;
  5695.  
  5696.     case HTML_PRE:                /* Formatted text */
  5697.     /*
  5698.      *  Set to know that we are no longer in a PRE block.
  5699.      */
  5700.     me->inPRE = FALSE;
  5701.     case HTML_LISTING:                /* Literal text */
  5702.     case HTML_XMP:
  5703.     case HTML_PLAINTEXT:
  5704.     if (me->comment_start)
  5705.         HText_appendText(me->text, me->comment_start);
  5706.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5707.     if (me->List_Nesting_Level >= 0) {
  5708.         UPDATE_STYLE;
  5709.         HText_NegateLineOne(me->text);
  5710.     }
  5711.     break;
  5712.  
  5713.     case HTML_NOTE:
  5714.     case HTML_FN:
  5715.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5716.     UPDATE_STYLE;
  5717.     if (me->sp->tag_number == element_number)
  5718.         LYEnsureDoubleSpace(me);
  5719.     if (me->List_Nesting_Level >= 0)
  5720.         HText_NegateLineOne(me->text);
  5721.     me->inLABEL = FALSE;
  5722.     break;
  5723.  
  5724.     case HTML_OL:
  5725.     me->OL_Counter[me->List_Nesting_Level < 11 ?
  5726.                 me->List_Nesting_Level : 11] = OL_VOID;
  5727.     case HTML_DL:
  5728.     case HTML_UL:
  5729.     case HTML_MENU:
  5730.     case HTML_DIR:
  5731.     me->List_Nesting_Level--;
  5732.     CTRACE(tfp, "HTML_end_element: Reducing List Nesting Level to %d\n",
  5733.             me->List_Nesting_Level);
  5734.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5735.     UPDATE_STYLE;
  5736.     if (me->List_Nesting_Level >= 0)
  5737.         LYEnsureSingleSpace(me);
  5738.     break;
  5739.  
  5740.     case HTML_SPAN:
  5741.     /*
  5742.      *  Should undo anything we did based on LANG and/or DIR
  5743.      *  attributes, and the me->node_anchor->charset and/or
  5744.      *  yet to be added structure elements. - FM
  5745.      */
  5746.     break;
  5747.  
  5748.     case HTML_BDO:
  5749.     /*
  5750.      *  Should undo anything we did based on DIR (and/or LANG)
  5751.      *  attributes, and the me->node_anchor->charset and/or
  5752.      *  yet to be added structure elements. - FM
  5753.      */
  5754.     break;
  5755.  
  5756.     case HTML_A:
  5757.     /*
  5758.      *  Ignore any spurious A end tags. - FM
  5759.      */
  5760.     if (me->inA == FALSE)
  5761.         break;
  5762.     /*
  5763.      *  Set to know that we are no longer in an anchor.
  5764.      */
  5765.     me->inA = FALSE;
  5766.  
  5767.     UPDATE_STYLE;
  5768.     if (me->inBoldA == TRUE && me->inBoldH == FALSE)
  5769.         HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
  5770.     HText_endAnchor(me->text, me->CurrentANum);
  5771.     me->CurrentANum = 0;
  5772.     me->inBoldA = FALSE;
  5773.     if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
  5774.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  5775.         me->inUnderline = TRUE;
  5776.     }
  5777.     break;
  5778.  
  5779.     case HTML_MAP:
  5780.     FREE(me->map_address);
  5781.     break;
  5782.  
  5783.     case HTML_BODYTEXT:
  5784.     /*
  5785.      *  We may need to look at this someday to deal with
  5786.      *  OBJECTs optimally, but just ignore it for now. - FM
  5787.      */
  5788.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5789.     break;
  5790.  
  5791.     case HTML_TEXTFLOW:
  5792.     /*
  5793.      *  We may need to look at this someday to deal with
  5794.      *  APPLETs optimally, but just ignore it for now. - FM
  5795.      */
  5796.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5797.     break;
  5798.  
  5799.     case HTML_FIG:
  5800.     if (me->inFIGwithP) {
  5801.         LYEnsureDoubleSpace(me);
  5802.     } else {
  5803.         HTML_put_character(me, ' ');  /* space char may be ignored */
  5804.     }
  5805.     LYResetParagraphAlignment(me);
  5806.     me->inFIGwithP = FALSE;
  5807.     me->inFIG = FALSE;
  5808.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  5809.     if (me->List_Nesting_Level >= 0) {
  5810.         UPDATE_STYLE;
  5811.         HText_NegateLineOne(me->text);
  5812.     }
  5813.     break;
  5814.  
  5815.     case HTML_OBJECT:
  5816.     /*
  5817.      *  Finish the data off.
  5818.      */
  5819.     {
  5820.         int s = 0, e = 0;
  5821.         char *start = NULL, *first_end = NULL;
  5822.         BOOL have_param = FALSE;
  5823.         char *data = NULL;
  5824.  
  5825.         HTChunkTerminate(&me->object);
  5826.         data = me->object.data;
  5827.         while ((cp = strchr(data, '<')) != NULL) {
  5828.         /*
  5829.          *  Look for nested OBJECTs.  This procedure
  5830.          *  could get tripped up if invalid comments
  5831.          *  are present in the content, or if an OBJECT
  5832.          *  end tag is present in a quoted attribute. - FM
  5833.          */
  5834.         if (!strncmp(cp, "<!--", 4)) {
  5835.             data = LYFindEndOfComment(cp);
  5836.             cp = data;
  5837.         } else if (s == 0 && !strncasecomp(cp, "<PARAM", 6)) {
  5838.             have_param = TRUE;
  5839.         } else if (!strncasecomp(cp, "<OBJECT", 7)) {
  5840.             if (s == 0)
  5841.             start = cp;
  5842.             s++;
  5843.         } else if (!strncasecomp(cp, "</OBJECT", 8)) {
  5844.             if (e == 0)
  5845.             first_end = cp;
  5846.             e++;
  5847.         }
  5848.         data = ++cp;
  5849.         }
  5850.         if (s > e) {
  5851.         /*
  5852.          *  We have nested OBJECT tags, and not yet all of the
  5853.          *  end tags, so restore an end tag to the content, and
  5854.          *  pass a dummy start tag to the SGML parser so that it
  5855.          *  will resume the accumulation of OBJECT content. - FM
  5856.          */
  5857.         CTRACE(tfp, "HTML: Nested OBJECT tags.  Recycling.\n");
  5858.         if (*include == NULL) {
  5859.             StrAllocCopy(*include, "<OBJECT>");
  5860.         } else {
  5861.             if (0 && strstr(*include, me->object.data) == NULL) {
  5862.             StrAllocCat(*include, "<OBJECT>");
  5863.             }
  5864.         }
  5865.         me->object.size--;
  5866.         HTChunkPuts(&me->object, "</OBJECT>");
  5867.         change_paragraph_style(me, me->sp->style);
  5868.         break;
  5869.         }
  5870.         if (s < e) {
  5871.         /*
  5872.          *  We had more end tags than start tags, so
  5873.          *  we have bad HTML or otherwise misparsed. - FM
  5874.          */
  5875.         if (TRACE) {
  5876.             fprintf(tfp,
  5877.   "Bad HTML: Unmatched OBJECT start and end tags.  Discarding content:\n%s\n",
  5878.                 me->object.data);
  5879.         } else if (!me->inBadHTML) {
  5880.             _statusline(BAD_HTML_USE_TRACE);
  5881.             me->inBadHTML = TRUE;
  5882.             sleep(MessageSecs);
  5883.         }
  5884.         goto End_Object;
  5885.         }
  5886.  
  5887.         /*
  5888.          *    OBJECT start and end tags are fully matched,
  5889.          *    assuming we weren't tripped up by comments
  5890.          *    or quoted attributes. - FM
  5891.          */
  5892.         CTRACE(tfp, "HTML:OBJECT content:\n%s\n", me->object.data);
  5893.  
  5894.         /*
  5895.          *    OBJECTs with DECLARE should be saved but
  5896.          *    not instantiated, and if nested, can have
  5897.          *    only other DECLAREd OBJECTs.  Until we have
  5898.          *    code to handle these, we'll just create an
  5899.          *    anchor for the ID, if present, and discard
  5900.          *    the content (sigh 8-). - FM
  5901.          */
  5902.         if (me->object_declare == TRUE) {
  5903.         if (me->object_id && *me->object_id)
  5904.             LYHandleID(me, me->object_id);
  5905.         CTRACE(tfp, "HTML: DECLAREd OBJECT.  Ignoring!\n");
  5906.         goto End_Object;
  5907.         }
  5908.  
  5909.         /*
  5910.          *    OBJECTs with NAME are for FORM submissions.
  5911.          *    We'll just create an anchor for the ID, if
  5912.          *    present, and discard the content until we
  5913.          *    have code to handle these. (sigh 8-). - FM
  5914.          */
  5915.         if (me->object_name != NULL) {
  5916.         if (me->object_id && *me->object_id)
  5917.             LYHandleID(me, me->object_id);
  5918.         CTRACE(tfp, "HTML: NAMEd OBJECT.  Ignoring!\n");
  5919.         goto End_Object;
  5920.         }
  5921.  
  5922.         /*
  5923.          *    Deal with any nested OBJECTs by descending
  5924.          *    to the inner-most OBJECT. - FM
  5925.          */
  5926.         if (s > 0) {
  5927.         if (start != NULL &&
  5928.             first_end != NULL && first_end > start) {
  5929.             /*
  5930.              *    Minumum requirements for the ad hoc parsing
  5931.              *    to have succeeded are met.  We'll hope that
  5932.              *    it did succeed. - FM
  5933.              */
  5934.             *first_end = '\0';
  5935.             data = NULL;
  5936.             StrAllocCopy(data, start);
  5937.             if (e > 1) {
  5938.             for (i = e; i > 1; i--) {
  5939.                 StrAllocCat(data, "</OBJECT><OBJECT>");
  5940.             }
  5941.             }
  5942.             StrAllocCat(data, "</OBJECT>");
  5943.             StrAllocCat(*include, data);
  5944.             CTRACE(tfp, "HTML: Recycling nested OBJECT%s.\n",
  5945.                     (e > 1) ? "s" : "");
  5946.             FREE(data);
  5947.             goto End_Object;
  5948.         } else {
  5949.             if (TRACE) {
  5950.             fprintf(tfp,
  5951.      "Bad HTML: Unmatched OBJECT start and end tags.  Discarding content.\n");
  5952.             } else if (!me->inBadHTML) {
  5953.             _statusline(BAD_HTML_USE_TRACE);
  5954.             me->inBadHTML = TRUE;
  5955.             sleep(MessageSecs);
  5956.             }
  5957.             goto End_Object;
  5958.         }
  5959.         }
  5960.  
  5961.         /*
  5962.          *    If it's content has SHAPES, convert it to FIG. - FM
  5963.          */
  5964.         if (me->object_shapes == TRUE) {
  5965.         CTRACE(tfp, "HTML: OBJECT has SHAPES.  Converting to FIG.\n");
  5966.         StrAllocCat(*include, "<FIG ISOBJECT IMAGEMAP");
  5967.         if (me->object_ismap == TRUE)
  5968.             StrAllocCat(*include, " IMAGEMAP");
  5969.         if (me->object_id != NULL) {
  5970.             StrAllocCat(*include, " ID=\"");
  5971.             StrAllocCat(*include, me->object_id);
  5972.             StrAllocCat(*include, "\"");
  5973.         }
  5974.         if (me->object_data != NULL &&
  5975.             me->object_classid == NULL) {
  5976.             StrAllocCat(*include, " SRC=\"");
  5977.             StrAllocCat(*include, me->object_data);
  5978.             StrAllocCat(*include, "\"");
  5979.         }
  5980.         StrAllocCat(*include, ">");
  5981.         me->object.size--;
  5982.         HTChunkPuts(&me->object, "</FIG>");
  5983.         HTChunkTerminate(&me->object);
  5984.         StrAllocCat(*include, me->object.data);
  5985.         goto End_Object;
  5986.         }
  5987.  
  5988.         /*
  5989.          *    If it has a USEMAP attribute and didn't have SHAPES,
  5990.          *    convert it to IMG. - FM
  5991.          */
  5992.         if (me->object_usemap != NULL) {
  5993.         CTRACE(tfp, "HTML: OBJECT has USEMAP.  Converting to IMG.\n");
  5994.  
  5995.         StrAllocCat(*include, "<IMG ISOBJECT");
  5996.         if (me->object_id != NULL) {
  5997.             /*
  5998.              *    Pass the ID. - FM
  5999.              */
  6000.             StrAllocCat(*include, " ID=\"");
  6001.             StrAllocCat(*include, me->object_id);
  6002.             StrAllocCat(*include, "\"");
  6003.         }
  6004.         if (me->object_data != NULL &&
  6005.             me->object_classid == NULL) {
  6006.             /*
  6007.              *    We have DATA with no CLASSID, so let's
  6008.              *    hope it' equivalent to an SRC. - FM
  6009.              */
  6010.             StrAllocCat(*include, " SRC=\"");
  6011.             StrAllocCat(*include, me->object_data);
  6012.             StrAllocCat(*include, "\"");
  6013.         }
  6014.         if (me->object_title != NULL) {
  6015.             /*
  6016.              *    Use the TITLE for both the MAP
  6017.              *    and the IMGs ALT. - FM
  6018.              */
  6019.             StrAllocCat(*include, " TITLE=\"");
  6020.             StrAllocCat(*include, me->object_title);
  6021.             StrAllocCat(*include, "\" ALT=\"");
  6022.             StrAllocCat(*include, me->object_title);
  6023.             StrAllocCat(*include, "\"");
  6024.         }
  6025.         /*
  6026.          *  Add the USEMAP, and an ISMAP if present. - FM
  6027.          */
  6028.         if (me->object_usemap != NULL) {
  6029.             StrAllocCat(*include, " USEMAP=\"");
  6030.             StrAllocCat(*include, me->object_usemap);
  6031.             if (me->object_ismap == TRUE)
  6032.             StrAllocCat(*include, "\" ISMAP>");
  6033.             else
  6034.             StrAllocCat(*include, "\">");
  6035.         } else {
  6036.             StrAllocCat(*include, ">");
  6037.         }
  6038.         goto End_Object;
  6039.         }
  6040.  
  6041.         /*
  6042.          *    Add an ID link if needed. - FM
  6043.          */
  6044.         if (me->object_id && *me->object_id)
  6045.         LYHandleID(me, me->object_id);
  6046.  
  6047.         /*
  6048.          *    Add the OBJECTs content if not empty. - FM
  6049.          */
  6050.         if (me->object.size > 1)
  6051.         StrAllocCat(*include, me->object.data);
  6052.  
  6053.         /*
  6054.          *    Create a link to the DATA, if desired, and
  6055.          *    we can rule out that it involves scripting
  6056.          *    code.  This a risky thing to do, but we can
  6057.          *    toggle clickable_images mode off if it really
  6058.          *    screws things up, and so we may as well give
  6059.          *    it a try. - FM
  6060.          */
  6061.         if (clickable_images) {
  6062.         if (me->object_data != NULL &&
  6063.             !have_param &&
  6064.             me->object_classid == NULL &&
  6065.             me->object_codebase == NULL &&
  6066.             me->object_codetype == NULL) {
  6067.             /*
  6068.              *    We have a DATA value and no need for scripting
  6069.              *    code, so close the current Anchor, if one is
  6070.              *    open, and add an Anchor for this source.  If
  6071.              *    we also have a TYPE value, check whether it's
  6072.              *    an image or not, and set the link name
  6073.              *    accordingly. - FM
  6074.              */
  6075.             if (me->inA)
  6076.             StrAllocCat(*include, "</A>");
  6077.             StrAllocCat(*include, " -<A HREF=\"");
  6078.             StrAllocCat(*include, me->object_data);
  6079.             StrAllocCat(*include, "\">");
  6080.             if ((me->object_type != NULL) &&
  6081.             !strncasecomp(me->object_type, "image/", 6)) {
  6082.             StrAllocCat(*include, "(IMAGE)");
  6083.             } else {
  6084.             StrAllocCat(*include, "(OBJECT)");
  6085.             }
  6086.             StrAllocCat(*include, "</A> ");
  6087.         }
  6088.         }
  6089.     }
  6090.  
  6091.     /*
  6092.      *  Re-intialize all of the OBJECT elements. - FM
  6093.      */
  6094. End_Object:
  6095.     HTChunkClear(&me->object);
  6096.     me->object_started = FALSE;
  6097.     me->object_declare = FALSE;
  6098.     me->object_shapes = FALSE;
  6099.     me->object_ismap = FALSE;
  6100.     FREE(me->object_usemap);
  6101.     FREE(me->object_id);
  6102.     FREE(me->object_title);
  6103.     FREE(me->object_data);
  6104.     FREE(me->object_type);
  6105.     FREE(me->object_classid);
  6106.     FREE(me->object_codebase);
  6107.     FREE(me->object_codetype);
  6108.     FREE(me->object_name);
  6109.  
  6110.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  6111.     break;
  6112.  
  6113.     case HTML_APPLET:
  6114.     if (me->inAPPLETwithP) {
  6115.         LYEnsureDoubleSpace(me);
  6116.     } else {
  6117.         HTML_put_character(me, ' ');  /* space char may be ignored */
  6118.     }
  6119.     LYResetParagraphAlignment(me);
  6120.     me->inAPPLETwithP = FALSE;
  6121.     me->inAPPLET = FALSE;
  6122.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  6123.     break;
  6124.  
  6125.     case HTML_CAPTION:
  6126.     LYEnsureDoubleSpace(me);
  6127.     LYResetParagraphAlignment(me);
  6128.     me->inCAPTION = FALSE;
  6129.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  6130.     me->inLABEL = FALSE;
  6131.     break;
  6132.  
  6133.     case HTML_CREDIT:
  6134.     LYEnsureDoubleSpace(me);
  6135.     LYResetParagraphAlignment(me);
  6136.     me->inCREDIT = FALSE;
  6137.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  6138.     me->inLABEL = FALSE;
  6139.     break;
  6140.  
  6141.     case HTML_FORM:
  6142.     /*
  6143.      *  Check if we had a FORM start tag, and issue a
  6144.      *  message if not, but fall through to check for
  6145.      *  an open SELECT and ensure that the FORM-related
  6146.      *  globals in GridText.c are initialized. - FM
  6147.      */
  6148.     if (!me->inFORM) {
  6149.         if (TRACE) {
  6150.         fprintf(tfp, "Bad HTML: Unmatched FORM end tag\n");
  6151.         } else if (!me->inBadHTML) {
  6152.         _statusline(BAD_HTML_USE_TRACE);
  6153.         me->inBadHTML = TRUE;
  6154.         sleep(MessageSecs);
  6155.         }
  6156.     }
  6157.  
  6158.     /*
  6159.      *  Check if we still have a SELECT element open.
  6160.      *  FORM may have been declared SGML_EMPTY in HTMLDTD.c,
  6161.      *  and in that case SGML_character() in SGML.c is
  6162.      *  not able to ensure correct nesting; or it may have
  6163.      *  failed to enforce valid nesting.  If a SELECT is open,
  6164.      *  issue a message, then
  6165.      *  call HTML_end_element() directly (with a
  6166.      *  check in that to bypass decrementing of the HTML
  6167.      *  parser's stack) to close the SELECT. - kw
  6168.      */
  6169.     if (me->inSELECT) {
  6170.         if (TRACE) {
  6171.         fprintf(tfp,
  6172.            "Bad HTML: Open SELECT at FORM end. Faking SELECT end tag. *****\n");
  6173.         } else if (!me->inBadHTML) {
  6174.         _statusline(BAD_HTML_USE_TRACE);
  6175.         me->inBadHTML = TRUE;
  6176.         sleep(MessageSecs);
  6177.         }
  6178.         if (me->sp->tag_number != HTML_SELECT) {
  6179.         SET_SKIP_STACK(HTML_SELECT);
  6180.         }
  6181.         HTML_end_element(me, HTML_SELECT, (char **)&include);
  6182.     }
  6183.  
  6184.     /*
  6185.      *  Set to know that we are no longer in an form.
  6186.      */
  6187.     me->inFORM = FALSE;
  6188.  
  6189.     HText_endForm(me->text);
  6190.     /*
  6191.      *  If we are in a list and are on the first line
  6192.      *  with no text following a bullet or number,
  6193.      *  don't force a newline.  This could happen if
  6194.      *  we were called from HTML_start_element() due
  6195.      *  to a missing FORM end tag. - FM
  6196.      */
  6197.     if (!(me->List_Nesting_Level >= 0 && !me->inP))
  6198.         LYEnsureSingleSpace(me);
  6199.     break;
  6200.  
  6201.     case HTML_FIELDSET:
  6202.     LYEnsureDoubleSpace(me);
  6203.     LYResetParagraphAlignment(me);
  6204.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  6205.     break;
  6206.  
  6207.     case HTML_LEGEND:
  6208.     LYEnsureDoubleSpace(me);
  6209.     LYResetParagraphAlignment(me);
  6210.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  6211.     break;
  6212.  
  6213.     case HTML_LABEL:
  6214.     break;
  6215.  
  6216.     case HTML_BUTTON:
  6217.     break;
  6218.  
  6219.     case HTML_TEXTAREA:
  6220.     {
  6221.         InputFieldData I;
  6222.         int chars;
  6223.         char *data;
  6224.  
  6225.         /*
  6226.          *    Make sure we had a textarea start tag.
  6227.          */
  6228.         if (!me->inTEXTAREA) {
  6229.         if (TRACE) {
  6230.             fprintf(tfp, "Bad HTML: Unmatched TEXTAREA end tag\n");
  6231.         } else if (!me->inBadHTML) {
  6232.             _statusline(BAD_HTML_USE_TRACE);
  6233.             me->inBadHTML = TRUE;
  6234.             sleep(MessageSecs);
  6235.         }
  6236.         break;
  6237.         }
  6238.  
  6239.         /*
  6240.          *    Set to know that we are no longer in a textarea tag.
  6241.          */
  6242.         me->inTEXTAREA = FALSE;
  6243.  
  6244.         /*
  6245.          *    Initialize.
  6246.          */
  6247.         I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL;
  6248.         I.disabled=NO; I.error=NULL; I.height= NULL; I.id=NULL;
  6249.         I.lang=NULL; I.max=NULL; I.maxlength=NULL; I.md=NULL;
  6250.         I.min=NULL; I.name=NULL; I.size=NULL; I.src=NULL;
  6251.         I.type=NULL; I.value=NULL; I.width=NULL;
  6252.         I.value_cs = current_char_set;
  6253.  
  6254.         UPDATE_STYLE;
  6255.         /*
  6256.          *    Before any input field add a space if necessary.
  6257.          */
  6258.         HTML_put_character(me, ' ');
  6259.         me->in_word = NO;
  6260.         /*
  6261.          *    Add a return.
  6262.          */
  6263.         HText_appendCharacter(me->text, '\r');
  6264.  
  6265.         /*
  6266.          *    Finish the data off.
  6267.          */
  6268.         HTChunkTerminate(&me->textarea);
  6269.         data = me->textarea.data;
  6270.         FREE(temp);
  6271.  
  6272.         I.type = "textarea";
  6273.         I.size = me->textarea_cols;
  6274.         I.name = me->textarea_name;
  6275.         I.name_cs = me->textarea_name_cs;
  6276.         I.accept_cs = me->textarea_accept_cs;
  6277.         me->textarea_accept_cs = NULL;
  6278.         I.disabled = me->textarea_disabled;
  6279.         I.id = me->textarea_id;
  6280.  
  6281.         /*
  6282.          *    SGML unescape any character references in TEXTAREA
  6283.          *    content, then parse it into individual lines
  6284.          *    to be handled as a series of INPUT fields (ugh!).
  6285.          *    Any raw 8-bit or multibyte characters already have been
  6286.          *    handled in relation to the display character set
  6287.          *    in SGML_character().
  6288.          */
  6289.         me->UsePlainSpace = TRUE;
  6290.  
  6291.         TRANSLATE_AND_UNESCAPE_ENTITIES5(&me->textarea.data,
  6292.                             me->UCLYhndl,
  6293.                             current_char_set,
  6294.                             me->UsePlainSpace, me->HiddenValue);
  6295.  
  6296.         /*
  6297.          *    Trim any trailing newlines and
  6298.          *    skip any lead newlines. - FM
  6299.          */
  6300.         if (*data != '\0') {
  6301.         cp = (data + strlen(data)) - 1;
  6302.         while (cp >= data && *cp == '\n') {
  6303.             *cp-- = '\0';
  6304.         }
  6305.         while (*data == '\n') {
  6306.             data++;
  6307.         }
  6308.         }
  6309.         /*
  6310.          *    Load the first text line, or set
  6311.          *    up for all blank rows. - FM
  6312.          */
  6313.         if ((cp = strchr(data, '\n')) != NULL) {
  6314.         *cp = '\0';
  6315.         StrAllocCopy(temp, data);
  6316.         *cp = '\n';
  6317.         data = (cp + 1);
  6318.         } else {
  6319.         if (*data != '\0') {
  6320.             StrAllocCopy(temp, data);
  6321.         } else {
  6322.             FREE(temp);
  6323.         }
  6324.         data = "";
  6325.         }
  6326.         /*
  6327.          *    Display at least the requested number
  6328.          *    of text lines and/or blank rows. - FM
  6329.          */
  6330.         for (i = 0; i < me->textarea_rows; i++) {
  6331.         int j;
  6332.         for (j = 0; temp && temp[j]; j++) {
  6333.             if (temp[j] == '\r')
  6334.             temp[j] = (temp[j+1] ? ' ' : '\0');
  6335.         }
  6336.         I.value = temp;
  6337.         chars = HText_beginInput(me->text, me->inUnderline, &I);
  6338.         for (; chars > 0; chars--)
  6339.             HTML_put_character(me, '_');
  6340.         HText_appendCharacter(me->text, '\r');
  6341.         if (*data != '\0') {
  6342.             if (*data == '\n') {
  6343.             FREE(temp);
  6344.             data++;
  6345.             } else if ((cp = strchr(data, '\n')) != NULL) {
  6346.             *cp = '\0';
  6347.             StrAllocCopy(temp, data);
  6348.             *cp = '\n';
  6349.             data = (cp + 1);
  6350.             } else {
  6351.             StrAllocCopy(temp, data);
  6352.             data = "";
  6353.             }
  6354.         } else {
  6355.             FREE(temp);
  6356.         }
  6357.         }
  6358.         /*
  6359.          *    Check for more data lines than the rows attribute.
  6360.          *    We add them to the display, because we support only
  6361.          *    horizontal and not also vertical scrolling. - FM
  6362.          */
  6363.         while (*data != '\0' || temp != NULL) {
  6364.         int j;
  6365.         for (j = 0; temp && temp[j]; j++) {
  6366.             if (temp[j] == '\r')
  6367.             temp[j] = (temp[j+1] ? ' ' : '\0');
  6368.         }
  6369.         I.value = temp;
  6370.         chars = HText_beginInput(me->text, me->inUnderline, &I);
  6371.         for (chars = atoi(me->textarea_cols); chars > 0; chars--)
  6372.             HTML_put_character(me, '_');
  6373.         HText_appendCharacter(me->text, '\r');
  6374.         if (*data == '\n') {
  6375.             FREE(temp);
  6376.             data++;
  6377.         } else if ((cp = strchr(data, '\n')) != NULL) {
  6378.             *cp = '\0';
  6379.             StrAllocCopy(temp, data);
  6380.             *cp = '\n';
  6381.             data = (cp + 1);
  6382.         } else if (*data != '\0') {
  6383.             StrAllocCopy(temp, data);
  6384.             data = "";
  6385.         } else {
  6386.             FREE(temp);
  6387.         }
  6388.         }
  6389.         FREE(temp);
  6390.         cp = NULL;
  6391.         me->UsePlainSpace = FALSE;
  6392.  
  6393.         HTChunkClear(&me->textarea);
  6394.         FREE(me->textarea_name);
  6395.         me->textarea_name_cs = -1;
  6396.         FREE(me->textarea_cols);
  6397.         FREE(me->textarea_id);
  6398.         break;
  6399.     }
  6400.  
  6401.     case HTML_SELECT:
  6402.     {
  6403.         char *ptr;
  6404.  
  6405.         /*
  6406.          *    Make sure we had a select start tag.
  6407.          */
  6408.         if (!me->inSELECT) {
  6409.         if (TRACE) {
  6410.             fprintf(tfp, "Bad HTML: Unmatched SELECT end tag *****\n");
  6411.         } else if (!me->inBadHTML) {
  6412.             _statusline(BAD_HTML_USE_TRACE);
  6413.             me->inBadHTML = TRUE;
  6414.             sleep(MessageSecs);
  6415.         }
  6416.         break;
  6417.         }
  6418.  
  6419.         /*
  6420.          *    Set to know that we are no longer in a select tag.
  6421.          */
  6422.         me->inSELECT = FALSE;
  6423.  
  6424.         /*
  6425.          *    Clear the disable attribute.
  6426.          */
  6427.         me->select_disabled = FALSE;
  6428.  
  6429.         /*
  6430.          *    Make sure we're in a form.
  6431.          */
  6432.         if (!me->inFORM) {
  6433.         if (TRACE) {
  6434.             fprintf(tfp,
  6435.                 "Bad HTML: SELECT end tag not within FORM element *****\n");
  6436.         } else if (!me->inBadHTML) {
  6437.             _statusline(BAD_HTML_USE_TRACE);
  6438.             me->inBadHTML = TRUE;
  6439.             sleep(MessageSecs);
  6440.         }
  6441.         /*
  6442.          *  Hopefully won't crash, so we'll ignore it. - kw
  6443.          */
  6444.         }
  6445.  
  6446.         /*
  6447.          *    Finish the data off.
  6448.          */
  6449.         HTChunkTerminate(&me->option);
  6450.         /*
  6451.          *    Finish the previous option.
  6452.          */
  6453.         ptr = HText_setLastOptionValue(me->text,
  6454.                        me->option.data,
  6455.                        me->LastOptionValue,
  6456.                        LAST_ORDER,
  6457.                        me->LastOptionChecked,
  6458.                        me->UCLYhndl,
  6459.                        ATTR_CS_IN);
  6460.         FREE(me->LastOptionValue);
  6461.  
  6462.         me->LastOptionChecked = FALSE;
  6463.  
  6464.         if (HTCurSelectGroupType == F_CHECKBOX_TYPE ||
  6465.         LYSelectPopups == FALSE) {
  6466.             /*
  6467.              *    Start a newline after the last checkbox/button option.
  6468.              */
  6469.             LYEnsureSingleSpace(me);
  6470.         } else {
  6471.         /*
  6472.          *  Output popup box with the default option to screen,
  6473.          *  but use non-breaking spaces for output.
  6474.          */
  6475.         if (ptr &&
  6476.             (me->sp[0].tag_number == HTML_PRE || me->inPRE == TRUE ||
  6477.              !me->sp->style->freeFormat) &&
  6478.             strlen(ptr) > 6) {
  6479.             /*
  6480.              *    The code inadequately handles OPTION fields in PRE tags.
  6481.              *    We'll put up a minimum of 6 characters, and if any
  6482.              *    more would exceed the wrap column, we'll ignore them.
  6483.              */
  6484.             for (i = 0; i < 6; i++) {
  6485.             if (*ptr == ' ')
  6486.                 HText_appendCharacter(me->text,HT_NON_BREAK_SPACE);
  6487.             else
  6488.                 HText_appendCharacter(me->text,*ptr);
  6489.             ptr++;
  6490.             }
  6491.             HText_setIgnoreExcess(me->text, TRUE);
  6492.         }
  6493.         for (; ptr && *ptr != '\0'; ptr++) {
  6494.             if (*ptr == ' ')
  6495.             HText_appendCharacter(me->text,HT_NON_BREAK_SPACE);
  6496.             else
  6497.             HText_appendCharacter(me->text,*ptr);
  6498.         }
  6499.         /*
  6500.          *  Add end option character.
  6501.          */
  6502.         if (!me->first_option) {
  6503.             HText_appendCharacter(me->text, ']');
  6504.             HText_setLastChar(me->text, ']');
  6505.             me->in_word = YES;
  6506.         }
  6507.         HText_setIgnoreExcess(me->text, FALSE);
  6508.         }
  6509.         HTChunkClear(&me->option);
  6510.  
  6511.         if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
  6512.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  6513.         me->inUnderline = TRUE;
  6514.         }
  6515.         if (me->needBoldH == TRUE && me->inBoldH == FALSE) {
  6516.         HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
  6517.         me->inBoldH = TRUE;
  6518.         me->needBoldH = FALSE;
  6519.         }
  6520.     }
  6521.     break;
  6522.  
  6523.     case HTML_TABLE:
  6524.     me->inTABLE = FALSE;
  6525.     if (!strcmp(me->sp->style->name, "Preformatted")) {
  6526.         break;
  6527.     }
  6528.     if (me->Division_Level >= 0)
  6529.         me->Division_Level--;
  6530.     if (me->Division_Level >= 0)
  6531.         me->sp->style->alignment =
  6532.                 me->DivisionAlignments[me->Division_Level];
  6533.     change_paragraph_style(me, me->sp->style);
  6534.     UPDATE_STYLE;
  6535.     me->current_default_alignment = me->sp->style->alignment;
  6536.     if (me->List_Nesting_Level >= 0)
  6537.         HText_NegateLineOne(me->text);
  6538.     break;
  6539.  
  6540. /* These TABLE related elements may now not be SGML_EMPTY. - kw */
  6541.     case HTML_TR:
  6542.     break;
  6543.  
  6544.     case HTML_THEAD:
  6545.     case HTML_TFOOT:
  6546.     case HTML_TBODY:
  6547.     break;
  6548.  
  6549.     case HTML_COLGROUP:
  6550.     break;
  6551.  
  6552.     case HTML_TH:
  6553.     break;
  6554.  
  6555.     case HTML_TD:
  6556.     break;
  6557.  
  6558. /* More stuff that may now not be SGML_EMPTY any more: */
  6559.     case HTML_DT:
  6560.     case HTML_DD:
  6561.     case HTML_LH:
  6562.     case HTML_LI:
  6563.     case HTML_OVERLAY:
  6564.     break;
  6565.  
  6566.     case HTML_MATH:
  6567.     /*
  6568.      *  We're getting it as Literal text, which, until we can process
  6569.      *  it, we'll display as is, within brackets to alert the user. - FM
  6570.      */
  6571.     HTChunkPutc(&me->math, ' ');
  6572.     HTChunkTerminate(&me->math);
  6573.     if (me->math.size > 2) {
  6574.         LYEnsureSingleSpace(me);
  6575.         if (me->inUnderline == FALSE)
  6576.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  6577.         HTML_put_string(me, "[MATH:");
  6578.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  6579.         HTML_put_character(me, ' ');
  6580.         HTML_put_string(me, me->math.data);
  6581.         HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
  6582.         HTML_put_string(me, ":MATH]");
  6583.         if (me->inUnderline == FALSE)
  6584.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  6585.         LYEnsureSingleSpace(me);
  6586.     }
  6587.     HTChunkClear(&me->math);
  6588.     break;
  6589.  
  6590.     default:
  6591.     change_paragraph_style(me, me->sp->style);  /* Often won't really change */
  6592.     break;
  6593.  
  6594.     } /* switch */
  6595. #ifdef USE_COLOR_STYLE
  6596.     {
  6597.     char *end, *start=NULL, *lookfrom;
  6598.     char tmp[64];
  6599.     sprintf(tmp, ";%s", HTML_dtd.tags[element_number].name);
  6600.     strtolower(tmp);
  6601.  
  6602.     lookfrom = Style_className;
  6603.     do
  6604.     {
  6605.         end = start;
  6606.         start = strstr(lookfrom, tmp);
  6607.         if (start)
  6608.         lookfrom = start + 1;
  6609.     }
  6610.     while (start);
  6611. /* trim the last matching element off the end
  6612. ** - should match classes here as well (rp)
  6613. */
  6614.     if (end)
  6615.         *end='\0';
  6616.     hcode = hash_code(lookfrom && *lookfrom ? lookfrom : &tmp[1]);
  6617.     CTRACE(tfp, "CSS:%s (trimmed %s, END_ELEMENT)\n", Style_className, tmp);
  6618.     }
  6619.  
  6620. #if defined(DICKEY_TEST)
  6621.     if (HTML_dtd.tags[element_number].contents != SGML_EMPTY)
  6622. #endif
  6623.     {
  6624.     CTRACE(tfp, "STYLE:end_element: ending non-EMPTY style\n");
  6625. #if !defined(USE_HASH)
  6626.     HText_characterStyle(me->text, element_number+STARTAT, STACK_OFF);
  6627. #else
  6628.     HText_characterStyle(me->text, hcode, STACK_OFF);
  6629. #endif /* USE_HASH */
  6630. #if defined(PREVAIL)
  6631.     /* reset the prevailing class to the previous one */
  6632.     {
  6633.         char *dot=strrchr(Style_className,'.');
  6634.         LYstrncpy(prevailing_class,
  6635.               dot ? (char*)(dot+1) : "",
  6636.               (TEMPSTRINGSIZE - 1));
  6637.     }
  6638. #endif
  6639.     }
  6640. #endif /* USE_COLOR_STYLE */
  6641. }
  6642.  
  6643. /*        Expanding entities
  6644. **        ------------------
  6645. */
  6646. /*    (In fact, they all shrink!)
  6647. */
  6648. PUBLIC int HTML_put_entity ARGS2(HTStructured *, me, int, entity_number)
  6649. {
  6650.     int nent = HTML_dtd.number_of_entities;
  6651.  
  6652.     if (entity_number < nent) {
  6653.     HTML_put_string(me, p_entity_values[entity_number]);
  6654.     return HT_OK;
  6655.     }
  6656.     return HT_CANNOT_TRANSLATE;
  6657. }
  6658.  
  6659. /*    Free an HTML object
  6660. **    -------------------
  6661. **
  6662. **    If the document is empty, the text object will not yet exist.
  6663. **    So we could in fact abandon creating the document and return
  6664. **    an error code.    In fact an empty document is an important type
  6665. **    of document, so we don't.
  6666. **
  6667. **    If non-interactive, everything is freed off.   No: crashes -listrefs
  6668. **    Otherwise, the interactive object is left.
  6669. */
  6670. PRIVATE void HTML_free ARGS1(HTStructured *, me)
  6671. {
  6672.     char *include = NULL;
  6673.  
  6674.     if (LYMapsOnly && !me->text) {
  6675.     /*
  6676.      *  We only handled MAP, AREA and BASE tags, and didn't
  6677.      *  create an HText structure for the document nor want
  6678.      *  one now, so just make sure we free anything that might
  6679.      *  have been allocated. - FM
  6680.      */
  6681.     FREE(me->base_href);
  6682.     FREE(me->map_address);
  6683.     FREE(me);
  6684.     return;
  6685.     }
  6686.  
  6687.     UPDATE_STYLE;        /* Creates empty document here! */
  6688.     if (me->comment_end)
  6689.     HTML_put_string(me, me->comment_end);
  6690.     if (me->text) {
  6691.     /*
  6692.      *  Emphasis containers, A, FONT, and FORM may be declared
  6693.      *  SGML_EMPTY in HTMLDTD.c, and SGML_character() in SGML.c
  6694.      *  may check for their end tags to call HTML_end_element()
  6695.      *  directly (with a check in that to bypass decrementing
  6696.      *  of the HTML parser's stack).  So if we still have the
  6697.      *  emphasis (Underline) on, or any open A, FONT, or FORM
  6698.      *  containers, turn it off or close them now. - FM & kw
  6699.      *
  6700.      *  IF those tags are not declared SGML_EMPTY, but we let
  6701.      *  the SGML.c parser take care of correctly stacked ordering,
  6702.      *  and of correct wind-down on end-of-stream (in SGML_free
  6703.      *  SGML_abort),
  6704.      *  THEN these and other checks here in HTML.c should not be
  6705.      *  necessary.    Still it can't hurt to include them. - kw
  6706.      */
  6707.     if (me->inUnderline) {
  6708.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  6709.         me->inUnderline = FALSE;
  6710.         me->Underline_Level = 0;
  6711.         CTRACE(tfp,"HTML_free: Ending underline\n");
  6712.     }
  6713.     if (me->inA) {
  6714.         HTML_end_element(me, HTML_A, (char **)&include);
  6715.         me->inA = FALSE;
  6716.     }
  6717.     if (me->inFONT) {
  6718.         HTML_end_element(me, HTML_FONT, (char **)&include);
  6719.         me->inFONT = FALSE;
  6720.     }
  6721.     if (me->inFORM) {
  6722.         HTML_end_element(me, HTML_FORM, (char **)&include);
  6723.         me->inFORM = FALSE;
  6724.     }
  6725.     if (me->option.size > 0) {
  6726.         /*
  6727.          *    If we still have data in the me->option chunk after
  6728.          *    forcing a close of a still-open form, something must
  6729.          *    have gone very wrong. - kw
  6730.          */
  6731.         if (TRACE) {
  6732.         fprintf(tfp,
  6733.             "Bad HTML: SELECT or OPTION not ended properly *****\n");
  6734.         } else if (!me->inBadHTML) {
  6735.         _statusline(BAD_HTML_USE_TRACE);
  6736.         me->inBadHTML = TRUE;
  6737.         sleep(MessageSecs);
  6738.         }
  6739.         HTChunkTerminate(&me->option);
  6740.         /*
  6741.          *    Output the left-over data as text, maybe it was invalid
  6742.          *    markup meant to be shown somewhere. - kw
  6743.          */
  6744.         CTRACE(tfp, "HTML_free: ***** leftover option data: %s\n",
  6745.             me->option.data);
  6746.         HTML_put_string(me, me->option.data);
  6747.         HTChunkClear(&me->option);
  6748.     }
  6749.     if (me->textarea.size > 0) {
  6750.         /*
  6751.          *    If we still have data in the me->textarea chunk after
  6752.          *    forcing a close of a still-open form, something must
  6753.          *    have gone very wrong. - kw
  6754.          */
  6755.         if (TRACE) {
  6756.         fprintf(tfp,
  6757.             "Bad HTML: TEXTAREA not used properly *****\n");
  6758.         } else if (!me->inBadHTML) {
  6759.         _statusline(BAD_HTML_USE_TRACE);
  6760.         me->inBadHTML = TRUE;
  6761.         sleep(MessageSecs);
  6762.         }
  6763.         HTChunkTerminate(&me->textarea);
  6764.         /*
  6765.          *    Output the left-over data as text, maybe it was invalid
  6766.          *    markup meant to be shown somewhere. - kw
  6767.          */
  6768.         CTRACE(tfp, "HTML_free: ***** leftover textarea data: %s\n",
  6769.             me->textarea.data);
  6770.         HTML_put_string(me, me->textarea.data);
  6771.         HTChunkClear(&me->textarea);
  6772.     }
  6773.     /*
  6774.      *  If we're interactive and have hidden links but no visible
  6775.      *  links, add a message informing the user about this and
  6776.      *  suggesting use of the 'l'ist command. - FM
  6777.      */
  6778.     if (!dump_output_immediately &&
  6779.         HText_sourceAnchors(me->text) < 1 &&
  6780.         HText_HiddenLinkCount(me->text) > 0) {
  6781.         HTML_start_element(me, HTML_P, 0, 0, -1, (char **)&include);
  6782.         HTML_put_character(me, '[');
  6783.         HTML_start_element(me, HTML_EM, 0, 0, -1, (char **)&include);
  6784.         HTML_put_string(me,
  6785.         "Document has only hidden links. Use the 'l'ist command.");
  6786.         HTML_end_element(me, HTML_EM, (char **)&include);
  6787.         HTML_put_character(me, ']');
  6788.         HTML_end_element(me, HTML_P, (char **)&include);
  6789.     }
  6790.  
  6791.     /*
  6792.      *  Now call the cleanup function. - FM
  6793.      */
  6794.     HText_endAppend(me->text);
  6795.     }
  6796.     if (me->option.size > 0) {
  6797.     /*
  6798.      *  If we still have data in the me->option chunk after
  6799.      *  forcing a close of a still-open form, something must
  6800.      *  have gone very wrong. - kw
  6801.      */
  6802.     if (TRACE) {
  6803.         fprintf(tfp,
  6804.             "Bad HTML: SELECT or OPTION not ended properly *****\n");
  6805.     } else if (!me->inBadHTML) {
  6806.         _statusline(BAD_HTML_USE_TRACE);
  6807.         me->inBadHTML = TRUE;
  6808.         sleep(MessageSecs);
  6809.     }
  6810.     if (TRACE) {
  6811.         HTChunkTerminate(&me->option);
  6812.         fprintf(tfp, "HTML_free: ***** leftover option data: %s\n",
  6813.             me->option.data);
  6814.     }
  6815.     HTChunkClear(&me->option);
  6816.     }
  6817.     if (me->textarea.size > 0) {
  6818.     /*
  6819.      *  If we still have data in the me->textarea chunk after
  6820.      *  forcing a close of a still-open form, something must
  6821.      *  have gone very wrong. - kw
  6822.      */
  6823.     if (TRACE) {
  6824.         fprintf(tfp,
  6825.             "Bad HTML: TEXTAREA not used properly *****\n");
  6826.     } else if (!me->inBadHTML) {
  6827.         _statusline(BAD_HTML_USE_TRACE);
  6828.         me->inBadHTML = TRUE;
  6829.         sleep(MessageSecs);
  6830.     }
  6831.     if (TRACE) {
  6832.         HTChunkTerminate(&me->textarea);
  6833.         fprintf(tfp, "HTML_free: ***** leftover textarea data: %s\n",
  6834.             me->textarea.data);
  6835.     }
  6836.     HTChunkClear(&me->textarea);
  6837.     }
  6838.  
  6839.     if (me->target) {
  6840.     (*me->targetClass._free)(me->target);
  6841.     }
  6842.     if (me->sp && me->sp->style && me->sp->style->name) {
  6843.     if (!strcmp(me->sp->style->name, "DivCenter") ||
  6844.         !strcmp(me->sp->style->name, "HeadingCenter") ||
  6845.         !strcmp(me->sp->style->name, "Heading1")) {
  6846.         me->sp->style->alignment = HT_CENTER;
  6847.     } else if (!strcmp(me->sp->style->name, "DivRight") ||
  6848.            !strcmp(me->sp->style->name, "HeadingRight")) {
  6849.         me->sp->style->alignment = HT_RIGHT;
  6850.     } else    {
  6851.         me->sp->style->alignment = HT_LEFT;
  6852.     }
  6853.     styles[HTML_PRE]->alignment = HT_LEFT;
  6854.     }
  6855.     FREE(me->base_href);
  6856.     FREE(me->map_address);
  6857.     FREE(me->LastOptionValue);
  6858.     FREE(me);
  6859. }
  6860.  
  6861. PRIVATE void HTML_abort ARGS2(HTStructured *, me, HTError, e)
  6862. {
  6863.     char *include = NULL;
  6864.  
  6865.     if (me->text) {
  6866.     /*
  6867.      *  If we have emphasis on, or open A, FONT, or FORM
  6868.      *  containers, turn it off or close them now. - FM
  6869.      */
  6870.     if (me->inUnderline) {
  6871.         HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
  6872.         me->inUnderline = FALSE;
  6873.         me->Underline_Level = 0;
  6874.     }
  6875.     if (me->inA) {
  6876.         HTML_end_element(me, HTML_A, (char **)&include);
  6877.         me->inA = FALSE;
  6878.     }
  6879.     if (me->inFONT) {
  6880.         HTML_end_element(me, HTML_FONT, (char **)&include);
  6881.         me->inFONT = FALSE;
  6882.     }
  6883.     if (me->inFORM) {
  6884.         HTML_end_element(me, HTML_FORM, (char **)&include);
  6885.         me->inFORM = FALSE;
  6886.     }
  6887.  
  6888.     /*
  6889.      *  Now call the cleanup function. - FM
  6890.      */
  6891.     HText_endAppend(me->text);
  6892.     }
  6893.  
  6894.     if (me->option.size > 0) {
  6895.     /*
  6896.      *  If we still have data in the me->option chunk after
  6897.      *  forcing a close of a still-open form, something must
  6898.      *  have gone very wrong. - kw
  6899.      */
  6900.     if (TRACE) {
  6901.         fprintf(tfp,
  6902.             "HTML_abort: SELECT or OPTION not ended properly *****\n");
  6903.         HTChunkTerminate(&me->option);
  6904.         fprintf(tfp, "HTML_abort: ***** leftover option data: %s\n",
  6905.             me->option.data);
  6906.     }
  6907.     HTChunkClear(&me->option);
  6908.     }
  6909.     if (me->textarea.size > 0) {
  6910.     /*
  6911.      *  If we still have data in the me->textarea chunk after
  6912.      *  forcing a close of a still-open form, something must
  6913.      *  have gone very wrong. - kw
  6914.      */
  6915.     if (TRACE) {
  6916.         fprintf(tfp,
  6917.             "HTML_abort: TEXTAREA not used properly *****\n");
  6918.         HTChunkTerminate(&me->textarea);
  6919.         fprintf(tfp, "HTML_abort: ***** leftover textarea data: %s\n",
  6920.             me->textarea.data);
  6921.     }
  6922.     HTChunkClear(&me->textarea);
  6923.     }
  6924.  
  6925.     if (me->target) {
  6926.     (*me->targetClass._abort)(me->target, e);
  6927.     }
  6928.     if (me->sp && me->sp->style && me->sp->style->name) {
  6929.     if (!strcmp(me->sp->style->name, "DivCenter") ||
  6930.         !strcmp(me->sp->style->name, "HeadingCenter") ||
  6931.         !strcmp(me->sp->style->name, "Heading1")) {
  6932.         me->sp->style->alignment = HT_CENTER;
  6933.     } else if (!strcmp(me->sp->style->name, "DivRight") ||
  6934.            !strcmp(me->sp->style->name, "HeadingRight")) {
  6935.         me->sp->style->alignment = HT_RIGHT;
  6936.     } else    {
  6937.         me->sp->style->alignment = HT_LEFT;
  6938.     }
  6939.     styles[HTML_PRE]->alignment = HT_LEFT;
  6940.     }
  6941.     FREE(me->base_href);
  6942.     FREE(me->map_address);
  6943.     FREE(me->textarea_name);
  6944.     FREE(me->textarea_accept_cs);
  6945.     FREE(me->textarea_cols);
  6946.     FREE(me->textarea_id);
  6947.     FREE(me->LastOptionValue);
  6948.     FREE(me);
  6949. }
  6950.  
  6951. /*    Get Styles from style sheet
  6952. **    ---------------------------
  6953. */
  6954. PRIVATE void get_styles NOARGS
  6955. {
  6956.     default_style =        HTStyleNamed(styleSheet, "Normal");
  6957.  
  6958.     styles[HTML_H1] =        HTStyleNamed(styleSheet, "Heading1");
  6959.     styles[HTML_H2] =        HTStyleNamed(styleSheet, "Heading2");
  6960.     styles[HTML_H3] =        HTStyleNamed(styleSheet, "Heading3");
  6961.     styles[HTML_H4] =        HTStyleNamed(styleSheet, "Heading4");
  6962.     styles[HTML_H5] =        HTStyleNamed(styleSheet, "Heading5");
  6963.     styles[HTML_H6] =        HTStyleNamed(styleSheet, "Heading6");
  6964.     styles[HTML_HCENTER] =    HTStyleNamed(styleSheet, "HeadingCenter");
  6965.     styles[HTML_HLEFT] =    HTStyleNamed(styleSheet, "HeadingLeft");
  6966.     styles[HTML_HRIGHT] =    HTStyleNamed(styleSheet, "HeadingRight");
  6967.  
  6968.     styles[HTML_DCENTER] =    HTStyleNamed(styleSheet, "DivCenter");
  6969.     styles[HTML_DLEFT] =    HTStyleNamed(styleSheet, "DivLeft");
  6970.     styles[HTML_DRIGHT] =    HTStyleNamed(styleSheet, "DivRight");
  6971.  
  6972.     styles[HTML_DL] =        HTStyleNamed(styleSheet, "Glossary");
  6973.     /* nested list styles */
  6974.     styles[HTML_DL1] =        HTStyleNamed(styleSheet, "Glossary1");
  6975.     styles[HTML_DL2] =        HTStyleNamed(styleSheet, "Glossary2");
  6976.     styles[HTML_DL3] =        HTStyleNamed(styleSheet, "Glossary3");
  6977.     styles[HTML_DL4] =        HTStyleNamed(styleSheet, "Glossary4");
  6978.     styles[HTML_DL5] =        HTStyleNamed(styleSheet, "Glossary5");
  6979.     styles[HTML_DL6] =        HTStyleNamed(styleSheet, "Glossary6");
  6980.  
  6981.     styles[HTML_UL] =
  6982.     styles[HTML_OL] =        HTStyleNamed(styleSheet, "List");
  6983.     /* nested list styles */
  6984.     styles[HTML_OL1] =        HTStyleNamed(styleSheet, "List1");
  6985.     styles[HTML_OL2] =        HTStyleNamed(styleSheet, "List2");
  6986.     styles[HTML_OL3] =        HTStyleNamed(styleSheet, "List3");
  6987.     styles[HTML_OL4] =        HTStyleNamed(styleSheet, "List4");
  6988.     styles[HTML_OL5] =        HTStyleNamed(styleSheet, "List5");
  6989.     styles[HTML_OL6] =        HTStyleNamed(styleSheet, "List6");
  6990.  
  6991.     styles[HTML_MENU] =
  6992.     styles[HTML_DIR] =        HTStyleNamed(styleSheet, "Menu");
  6993.     /* nested list styles */
  6994.     styles[HTML_MENU1] =    HTStyleNamed(styleSheet, "Menu1");
  6995.     styles[HTML_MENU2] =    HTStyleNamed(styleSheet, "Menu2");
  6996.     styles[HTML_MENU3] =    HTStyleNamed(styleSheet, "Menu3");
  6997.     styles[HTML_MENU4] =    HTStyleNamed(styleSheet, "Menu4");
  6998.     styles[HTML_MENU5] =    HTStyleNamed(styleSheet, "Menu5");
  6999.     styles[HTML_MENU6] =    HTStyleNamed(styleSheet, "Menu6");
  7000.  
  7001.     styles[HTML_DLC] =        HTStyleNamed(styleSheet, "GlossaryCompact");
  7002.     /* nested list styles */
  7003.     styles[HTML_DLC1] =     HTStyleNamed(styleSheet, "GlossaryCompact1");
  7004.     styles[HTML_DLC2] =     HTStyleNamed(styleSheet, "GlossaryCompact2");
  7005.     styles[HTML_DLC3] =     HTStyleNamed(styleSheet, "GlossaryCompact3");
  7006.     styles[HTML_DLC4] =     HTStyleNamed(styleSheet, "GlossaryCompact4");
  7007.     styles[HTML_DLC5] =     HTStyleNamed(styleSheet, "GlossaryCompact5");
  7008.     styles[HTML_DLC6] =     HTStyleNamed(styleSheet, "GlossaryCompact6");
  7009.  
  7010.     styles[HTML_ADDRESS] =    HTStyleNamed(styleSheet, "Address");
  7011.     styles[HTML_BANNER] =    HTStyleNamed(styleSheet, "Banner");
  7012.     styles[HTML_BLOCKQUOTE] =    HTStyleNamed(styleSheet, "Blockquote");
  7013.     styles[HTML_BQ] =        HTStyleNamed(styleSheet, "Bq");
  7014.     styles[HTML_FN] =        HTStyleNamed(styleSheet, "Footnote");
  7015.     styles[HTML_NOTE] =     HTStyleNamed(styleSheet, "Note");
  7016.     styles[HTML_PLAINTEXT] =
  7017.     styles[HTML_XMP] =        HTStyleNamed(styleSheet, "Example");
  7018.     styles[HTML_PRE] =        HTStyleNamed(styleSheet, "Preformatted");
  7019.     styles[HTML_LISTING] =    HTStyleNamed(styleSheet, "Listing");
  7020. }
  7021.  
  7022. /*                P U B L I C
  7023. */
  7024.  
  7025. /*    Structured Object Class
  7026. **    -----------------------
  7027. */
  7028. PUBLIC CONST HTStructuredClass HTMLPresentation = /* As opposed to print etc */
  7029. {
  7030.     "Lynx_HTML_Handler",
  7031.     HTML_free,
  7032.     HTML_abort,
  7033.     HTML_put_character,    HTML_put_string,  HTML_write,
  7034.     HTML_start_element,    HTML_end_element,
  7035.     HTML_put_entity
  7036. };
  7037.  
  7038. /*        New Structured Text object
  7039. **        --------------------------
  7040. **
  7041. **    The structured stream can generate either presentation,
  7042. **    or plain text, or HTML.
  7043. */
  7044. PUBLIC HTStructured* HTML_new ARGS3(
  7045.     HTParentAnchor *,    anchor,
  7046.     HTFormat,        format_out,
  7047.     HTStream*,        stream)
  7048. {
  7049.  
  7050.     HTStructured * me;
  7051.  
  7052.     if (format_out != WWW_PLAINTEXT && format_out != WWW_PRESENT) {
  7053.     HTStream * intermediate = HTStreamStack(WWW_HTML, format_out,
  7054.                         stream, anchor);
  7055.     if (intermediate)
  7056.         return HTMLGenerator(intermediate);
  7057.     fprintf(stderr, "\n** Internal error: can't parse HTML to %s\n",
  7058.         HTAtom_name(format_out));
  7059. #ifndef NOSIGHUP
  7060.     (void) signal(SIGHUP, SIG_DFL);
  7061. #endif /* NOSIGHUP */
  7062.     (void) signal(SIGTERM, SIG_DFL);
  7063. #ifndef VMS
  7064.     (void) signal(SIGINT, SIG_DFL);
  7065. #endif /* !VMS */
  7066. #ifdef SIGTSTP
  7067.     if (no_suspend)
  7068.       (void) signal(SIGTSTP,SIG_DFL);
  7069. #endif /* SIGTSTP */
  7070.     exit (-1);
  7071.     }
  7072.  
  7073.     me = (HTStructured*) calloc(sizeof(*me),1);
  7074.     if (me == NULL)
  7075.     outofmem(__FILE__, "HTML_new");
  7076.  
  7077.     /*
  7078.      * This used to call 'get_styles()' only on the first time through this
  7079.      * function.  However, if the user reloads a page with ^R, the styles[]
  7080.      * array is not necessarily the same as it was from 'get_styles()'.  So
  7081.      * we reinitialize the whole thing.
  7082.      */
  7083.     styleSheet = DefaultStyle();
  7084.     get_styles();
  7085.  
  7086.     me->isa = &HTMLPresentation;
  7087.     me->node_anchor = anchor;
  7088.  
  7089.     me->CurrentA = NULL;
  7090.     me->CurrentANum = 0;
  7091.     me->base_href = NULL;
  7092.     me->map_address = NULL;
  7093.  
  7094.     me->title.size = 0;
  7095.     me->title.growby = 128;
  7096.     me->title.allocated = 0;
  7097.     me->title.data = NULL;
  7098.  
  7099.     me->object.size = 0;
  7100.     me->object.growby = 128;
  7101.     me->object.allocated = 0;
  7102.     me->object.data = NULL;
  7103.     me->object_started = FALSE;
  7104.     me->object_declare = FALSE;
  7105.     me->object_shapes = FALSE;
  7106.     me->object_ismap = FALSE;
  7107.     me->object_id = NULL;
  7108.     me->object_title = NULL;
  7109.     me->object_data = NULL;
  7110.     me->object_type = NULL;
  7111.     me->object_classid = NULL;
  7112.     me->object_codebase = NULL;
  7113.     me->object_codetype = NULL;
  7114.     me->object_usemap = NULL;
  7115.     me->object_name = NULL;
  7116.  
  7117.     me->option.size = 0;
  7118.     me->option.growby = 128;
  7119.     me->option.allocated = 0;
  7120.     me->option.data = NULL;
  7121.     me->first_option = TRUE;
  7122.     me->LastOptionValue = NULL;
  7123.     me->LastOptionChecked = FALSE;
  7124.     me->select_disabled = FALSE;
  7125.  
  7126.     me->textarea.size = 0;
  7127.     me->textarea.growby = 128;
  7128.     me->textarea.allocated = 0;
  7129.     me->textarea.data = NULL;
  7130.     me->textarea_name = NULL;
  7131.     me->textarea_name_cs = -1;
  7132.     me->textarea_accept_cs = NULL;
  7133.     me->textarea_cols = NULL;
  7134.     me->textarea_rows = 4;
  7135.     me->textarea_disabled = NO;
  7136.     me->textarea_id = NULL;
  7137.  
  7138.     me->math.size = 0;
  7139.     me->math.growby = 128;
  7140.     me->math.allocated = 0;
  7141.     me->math.data = NULL;
  7142.  
  7143.     me->style_block.size = 0;
  7144.     me->style_block.growby = 128;
  7145.     me->style_block.allocated = 0;
  7146.     me->style_block.data = NULL;
  7147.  
  7148.     me->script.size = 0;
  7149.     me->script.growby = 128;
  7150.     me->script.allocated = 0;
  7151.     me->script.data = NULL;
  7152.  
  7153.     me->text = 0;
  7154.     me->style_change = YES;    /* Force check leading to text creation */
  7155.     me->new_style = default_style;
  7156.     me->old_style = 0;
  7157.     me->current_default_alignment = HT_LEFT;
  7158.     me->sp = (me->stack + MAX_NESTING - 1);
  7159.     me->skip_stack = 0;
  7160.     me->sp->tag_number = -1;                /* INVALID */
  7161.     me->sp->style = default_style;            /* INVALID */
  7162.     me->sp->style->alignment = HT_LEFT;
  7163.     me->stack_overrun = FALSE;
  7164.  
  7165.     me->Division_Level = -1;
  7166.     me->Underline_Level = 0;
  7167.     me->Quote_Level = 0;
  7168.  
  7169.     me->UsePlainSpace = FALSE;
  7170.     me->HiddenValue = FALSE;
  7171.     me->lastraw = -1;
  7172.  
  7173.     /*
  7174.      *    Used for nested lists. - FM
  7175.      */
  7176.     me->List_Nesting_Level = -1; /* counter for list nesting level */
  7177.     LYZero_OL_Counter(me);     /* Initializes OL_Counter[] and OL_Type[] */
  7178.     me->Last_OL_Count = 0;     /* last count in ordered lists */
  7179.     me->Last_OL_Type = '1';     /* last type in ordered lists */
  7180.  
  7181.     me->inA = FALSE;
  7182.     me->inAPPLET = FALSE;
  7183.     me->inAPPLETwithP = FALSE;
  7184.     me->inBadBASE = FALSE;
  7185.     me->inBadHREF = FALSE;
  7186.     me->inBadHTML = FALSE;
  7187.     me->inBASE = FALSE;
  7188.     me->inBoldA = FALSE;
  7189.     me->inBoldH = FALSE;
  7190.     me->inCAPTION = FALSE;
  7191.     me->inCREDIT = FALSE;
  7192.     me->inFIG = FALSE;
  7193.     me->inFIGwithP = FALSE;
  7194.     me->inFONT = FALSE;
  7195.     me->inFORM = FALSE;
  7196.     me->inLABEL = FALSE;
  7197.     me->inP = FALSE;
  7198.     me->inPRE = FALSE;
  7199.     me->inSELECT = FALSE;
  7200.     me->inTABLE = FALSE;
  7201.     me->inUnderline = FALSE;
  7202.  
  7203.     me->needBoldH = FALSE;
  7204.  
  7205.     me->comment_start = NULL;
  7206.     me->comment_end = NULL;
  7207.  
  7208. #ifdef USE_COLOR_STYLE
  7209.     Style_className[0] = '\0';
  7210.     class_string[0] = '\0';
  7211.     prevailing_class[0] = '\0';
  7212. #endif
  7213.  
  7214. #ifdef NOTUSED_FOTEMODS
  7215.     /*
  7216.     **    If the anchor already has stage info, make sure that it is
  7217.     **    appropriate for the current display charset.  HTMIMEConvert()
  7218.     **    does this for the http and https schemes, and HTCharsetFormat()
  7219.     **    does it for the file and and ftp schemes, be we need to do it,
  7220.     **    if necessary, for the gateway schemes. - FM
  7221.     */
  7222.     if (me->node_anchor->UCStages) {
  7223.     if (HTAnchor_getUCLYhndl(me->node_anchor,
  7224.                  UCT_STAGE_STRUCTURED) != current_char_set) {
  7225.         /*
  7226.         **    We are reloading due to a change in the display character
  7227.         **    set.  Free the stage info and let the stage info creation
  7228.         **    mechanisms create a new UCStages structure appropriate for
  7229.         **    the current display character set. - FM
  7230.         */
  7231.         FREE(anchor->UCStages);
  7232.     } else if (HTAnchor_getUCLYhndl(me->node_anchor,
  7233.                     UCT_STAGE_MIME) == current_char_set) {
  7234.         /*
  7235.         **    The MIME stage is set to the current display character
  7236.         **    set.  If it is CJK, and HTCJK does not point to a CJK
  7237.         **    character set, assume we are reloading due to a raw
  7238.         **    mode toggle and reset the MIME and PARSER stages to
  7239.         **    an ISO Latin 1 default. - FM
  7240.         */
  7241.         LYUCcharset *p_in = HTAnchor_getUCInfoStage(me->node_anchor,
  7242.                             UCT_STAGE_MIME);
  7243.         if (p_in->enc == UCT_ENC_CJK && HTCJK == NOCJK) {
  7244.         HTAnchor_resetUCInfoStage(me->node_anchor, 0,
  7245.                       UCT_STAGE_MIME,
  7246.                       UCT_SETBY_DEFAULT);
  7247.         HTAnchor_setUCInfoStage(me->node_anchor, 0,
  7248.                     UCT_STAGE_MIME,
  7249.                     UCT_SETBY_DEFAULT);
  7250.         HTAnchor_resetUCInfoStage(me->node_anchor, 0,
  7251.                       UCT_STAGE_PARSER,
  7252.                       UCT_SETBY_DEFAULT);
  7253.         HTAnchor_setUCInfoStage(me->node_anchor, 0,
  7254.                     UCT_STAGE_PARSER,
  7255.                     UCT_SETBY_DEFAULT);
  7256.         }
  7257.     }
  7258.     }
  7259. #endif /* NOTUSED_FOTEMODS */
  7260.  
  7261.     /*
  7262.     **    Create a chartrans stage info structure for the anchor,
  7263.     **    if it does not exist already (in which case the default
  7264.     **    MIME stage info will be loaded as well), and load the
  7265.     **    HTML stage info into me->UCI and me->UCLYhndl. - FM
  7266.     */
  7267.     LYGetChartransInfo(me);
  7268.     UCTransParams_clear(&me->T);
  7269.  
  7270.     /*
  7271.     **    Load the existing or default input charset info
  7272.     **    into the holding elements.  We'll believe what
  7273.     **    is indicated for UCT_STAGE_PARSER. - FM
  7274.     */
  7275.     me->inUCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,
  7276.                       UCT_STAGE_PARSER);
  7277.     if (me->inUCLYhndl < 0) {
  7278.     me->inUCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,
  7279.                           UCT_STAGE_MIME);
  7280.     me->inUCI = HTAnchor_getUCInfoStage(me->node_anchor,
  7281.                         UCT_STAGE_MIME);
  7282.     } else {
  7283.     me->inUCI = HTAnchor_getUCInfoStage(me->node_anchor,
  7284.                         UCT_STAGE_PARSER);
  7285.     }
  7286.  
  7287.     /*
  7288.     **    Load the existing or default output charset info
  7289.     **    into the holding elements, UCT_STAGE_STRUCTURED
  7290.     **    should be the same as UCT_STAGE_TEXT at this point,
  7291.     **    but we could check, perhaps. - FM
  7292.     */
  7293.     me->outUCI = HTAnchor_getUCInfoStage(me->node_anchor,
  7294.                      UCT_STAGE_STRUCTURED);
  7295.     me->outUCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,
  7296.                        UCT_STAGE_STRUCTURED);
  7297. #ifdef NOTUSED_FOTEMODS
  7298.     UCSetTransParams(&me->T,
  7299.              me->inUCLYhndl, me->inUCI,
  7300.              me->outUCLYhndl, me->outUCI);
  7301. #endif
  7302.  
  7303.     me->target = stream;
  7304.     if (stream)
  7305.     me->targetClass = *stream->isa;         /* Copy pointers */
  7306.  
  7307.     return (HTStructured*) me;
  7308. }
  7309.  
  7310. /*    HTConverter for HTML to plain text
  7311. **    ----------------------------------
  7312. **
  7313. **    This will convert from HTML to presentation or plain text.
  7314. */
  7315. PUBLIC HTStream* HTMLToPlain ARGS3(
  7316.     HTPresentation *,    pres,
  7317.     HTParentAnchor *,    anchor,
  7318.     HTStream *,        sink)
  7319. {
  7320.     return SGML_new(&HTML_dtd, anchor, HTML_new(anchor, pres->rep_out, sink));
  7321. }
  7322.  
  7323. /*    HTConverter for HTML source to plain text
  7324. **    -----------------------------------------
  7325. **
  7326. **    This will preparse HTML and convert back to presentation or plain text.
  7327. */
  7328. PUBLIC HTStream* HTMLParsedPresent ARGS3(
  7329.     HTPresentation *,    pres,
  7330.     HTParentAnchor *,    anchor,
  7331.     HTStream *,        sink)
  7332. {
  7333.     HTStream * intermediate = sink;
  7334.     if (!intermediate) {
  7335.     /*
  7336.      *  Trick to prevent HTPlainPresent from translating again.
  7337.      *  Temporarily change UCT_STAGE_PARSER setting in anchor
  7338.      *  while the HTPlain stream is initialized, so that HTPlain
  7339.      *  sees its input and output charsets as the same.  - kw
  7340.      */
  7341.     int old_parser_cset = HTAnchor_getUCLYhndl(anchor,UCT_STAGE_PARSER);
  7342.     int structured_cset = HTAnchor_getUCLYhndl(anchor,UCT_STAGE_STRUCTURED);
  7343.     if (structured_cset < 0)
  7344.         structured_cset = HTAnchor_getUCLYhndl(anchor,UCT_STAGE_HTEXT);
  7345.     if (structured_cset < 0)
  7346.         structured_cset = current_char_set;
  7347.     HTAnchor_setUCInfoStage(anchor, structured_cset,
  7348.                 UCT_STAGE_PARSER, UCT_SETBY_MIME);
  7349.     if (pres->rep_out == WWW_SOURCE) {
  7350. /*        intermediate = HTPlainPresent(pres, anchor, NULL); */
  7351.         intermediate = HTStreamStack(WWW_PLAINTEXT, WWW_PRESENT,
  7352.                      NULL, anchor);
  7353.     } else {
  7354.         intermediate = HTStreamStack(WWW_PLAINTEXT, pres->rep_out,
  7355.                      NULL, anchor);
  7356.     }
  7357.     if (old_parser_cset != structured_cset) {
  7358.         HTAnchor_resetUCInfoStage(anchor, old_parser_cset,
  7359.                       UCT_STAGE_PARSER, UCT_SETBY_NONE);
  7360.         if (old_parser_cset >= 0) {
  7361.         HTAnchor_setUCInfoStage(anchor, old_parser_cset,
  7362.                     UCT_STAGE_PARSER,
  7363.                     UCT_SETBY_DEFAULT+1);
  7364.         }
  7365.     }
  7366.     }
  7367.     if (!intermediate)
  7368.     return NULL;
  7369.     return SGML_new(&HTML_dtd, anchor, HTMLGenerator(intermediate));
  7370. }
  7371.  
  7372. /*    HTConverter for HTML to C code
  7373. **    ------------------------------
  7374. **
  7375. **    C code is like plain text but all non-preformatted code
  7376. **    is commented out.
  7377. **    This will convert from HTML to presentation or plain text.
  7378. */
  7379. PUBLIC HTStream* HTMLToC ARGS3(
  7380.     HTPresentation *,    pres GCC_UNUSED,
  7381.     HTParentAnchor *,    anchor,
  7382.     HTStream *,        sink)
  7383. {
  7384.     HTStructured * html;
  7385.  
  7386.     (*sink->isa->put_string)(sink, "/* ");    /* Before even title */
  7387.     html = HTML_new(anchor, WWW_PLAINTEXT, sink);
  7388.     html->comment_start = "/* ";
  7389.     html->comment_end = " */\n";    /* Must start in col 1 for cpp */
  7390. /*    HTML_put_string(html,html->comment_start); */
  7391.     return SGML_new(&HTML_dtd, anchor, html);
  7392. }
  7393.  
  7394. /*    Presenter for HTML
  7395. **    ------------------
  7396. **
  7397. **    This will convert from HTML to presentation or plain text.
  7398. **
  7399. **    Override this if you have a windows version
  7400. */
  7401. #ifndef GUI
  7402. PUBLIC HTStream* HTMLPresent ARGS3(
  7403.     HTPresentation *,    pres GCC_UNUSED,
  7404.     HTParentAnchor *,    anchor,
  7405.     HTStream *,        sink GCC_UNUSED)
  7406. {
  7407.     return SGML_new(&HTML_dtd, anchor, HTML_new(anchor, WWW_PRESENT, NULL));
  7408. }
  7409. #endif /* !GUI */
  7410.  
  7411. /*    Record error message as a hypertext object
  7412. **    ------------------------------------------
  7413. **
  7414. **    The error message should be marked as an error so that
  7415. **    it can be reloaded later.
  7416. **    This implementation just throws up an error message
  7417. **    and leaves the document unloaded.
  7418. **    A smarter implementation would load an error document,
  7419. **    marking at such so that it is retried on reload.
  7420. **
  7421. ** On entry,
  7422. **    sink    is a stream to the output device if any
  7423. **    number    is the HTTP error number
  7424. **    message is the human readable message.
  7425. **
  7426. ** On exit,
  7427. **    returns a negative number to indicate lack of success in the load.
  7428. */
  7429. PUBLIC int HTLoadError ARGS3(
  7430.     HTStream *,    sink GCC_UNUSED,
  7431.     int,        number,
  7432.     CONST char *,    message)
  7433. {
  7434.     HTAlert(message);        /* @@@@@@@@@@@@@@@@@@@ */
  7435.     return -number;
  7436. }
  7437.  
  7438.  
  7439. PRIVATE char * MakeNewTitle ARGS1(CONST char **, value)
  7440. {
  7441.     char *ptr;
  7442.     char *newtitle = NULL;
  7443.  
  7444.     StrAllocCopy(newtitle, "[");
  7445.     ptr = strrchr(value[HTML_IMG_SRC], '/');
  7446.     if (!ptr) {
  7447.     StrAllocCat(newtitle, value[HTML_IMG_SRC]);
  7448.     } else {
  7449.     StrAllocCat(newtitle, ptr + 1);
  7450.     }
  7451.     StrAllocCat(newtitle, "]");
  7452.     return newtitle;
  7453. }
  7454.