home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / text / hyper / hsc_source.lha / hsc / source / hsclib / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-23  |  31.5 KB  |  1,160 lines

  1. /*
  2.  * hsclib/parse.c
  3.  *
  4.  * parse file: handle for entities & tags
  5.  *
  6.  * Copyright (C) 1995,96  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * updated: 23-Jan-1997
  23.  * created:  1-Jul-1995
  24.  *
  25.  */
  26.  
  27. #define NOEXTERN_HSCLIB_PARSE_H
  28.  
  29. #include "hsclib/inc_base.h"
  30.  
  31. #include "hsclib/defattr.h"
  32. #include "hsclib/deftag.h"
  33. #include "hsclib/idref.h"
  34. #include "hsclib/include.h"
  35. #include "hsclib/input.h"
  36. #include "hsclib/parse.h"
  37. #include "hsclib/posteval.h"
  38. #include "hscprj/project.h"
  39. #include "hsclib/skip.h"
  40. #include "hsclib/size.h"
  41. #include "hsclib/uri.h"
  42.  
  43. /*
  44.  *---------------------------
  45.  * misc. functions
  46.  *---------------------------
  47.  */
  48.  
  49. /*
  50.  * message_rplc
  51.  *
  52.  * message that tells user that a special char
  53.  * was replaced by its entity
  54.  */
  55. static VOID message_rplc(HSCPRC * hp, STRPTR what, STRPTR by)
  56. {
  57.     hsc_message(hp, MSG_RPLC_ENT,
  58.                 "replaced %q by %q", what, by);
  59. }
  60.  
  61. /*
  62.  * check_mbinaw
  63.  *
  64.  * check if tag occures at a allowed position
  65.  */
  66. static BOOL check_mbinaw(HSCPRC * hp, HSCTAG * tag)
  67. {
  68.     BOOL ok = TRUE;
  69.  
  70.     /* check for tags that must be called before */
  71.     if (tag->mbi)
  72.     {
  73.         DLNODE *nd = hp->container_stack->first;
  74.         LONG found = 0;
  75.  
  76.         while (nd && !found)
  77.         {
  78.             HSCTAG *ctag = (HSCTAG *) nd->data;
  79.  
  80.             found = strenum(ctag->name, tag->mbi, '|', STEN_NOCASE);
  81.             nd = nd->next;
  82.  
  83.         }
  84.  
  85.         if (!found)
  86.         {
  87.             hsc_message(hp, MSG_MBI,
  88.                         "%T must be inside %t", tag, tag->mbi);
  89.             ok = FALSE;
  90.         }
  91.     }
  92.  
  93.     /* check for tags that are not to be called before */
  94.     if (tag->naw)
  95.     {
  96.         DLNODE *nd = hp->container_stack->first;
  97.         LONG found = 0;
  98.  
  99.         while (nd)
  100.         {
  101.             HSCTAG *ctag = (HSCTAG *) nd->data;
  102.  
  103.             found = strenum(ctag->name, tag->naw, '|', STEN_NOCASE);
  104.             if (found)
  105.             {
  106.                 hsc_message(hp, MSG_NAW,
  107.                             "%T not allowed within %C", tag, ctag);
  108.                 ok = FALSE;
  109.             }
  110.             nd = nd->next;
  111.         }
  112.     }
  113.     return (ok);
  114. }
  115.  
  116. /* enable output for a process */
  117. static void hp_enable_output(HSCPRC * hp, STRPTR cause)
  118. {
  119.     if (hp->suppress_output)
  120.     {
  121.         clr_estr(hp->whtspc);
  122.         D(fprintf(stderr, DHL "output enabled (%s)\n", cause));
  123.     }
  124.     hp->suppress_output = FALSE;
  125. }
  126.  
  127. /*
  128.  *---------------------------
  129.  * remove/append end tag
  130.  * from/to container_stack
  131.  *---------------------------
  132.  */
  133.  
  134. /*
  135.  * append_end_tag
  136.  *
  137.  * create end tag and append it to tag-list;
  138.  * also clone options & attribute list of parent
  139.  * tag, if tag is a macro and has a closing tag.
  140.  *
  141.  * params: hp.....hscprc with container_stack to be modified
  142.  *         tagid..name of the new tag (eg "IMG")
  143.  * result: ptr to the new tag or NULL if no mem
  144.  */
  145. HSCTAG *append_end_tag(HSCPRC * hp, HSCTAG * tag)
  146. {
  147.     HSCTAG *ctag;
  148.     DLLIST *taglist = hp->container_stack;
  149.  
  150.     ctag = new_hsctag(tag->name);
  151.     if (ctag)
  152.     {
  153.         BOOL ok = TRUE;
  154.         DLNODE *nd = NULL;
  155.  
  156.         /* copy important data of tag */
  157.         ctag->option = tag->option;
  158.  
  159.         /* clone attributes, if tag is a
  160.          * macro tag and has a closing tag
  161.          */
  162.         if ((tag->option & HT_MACRO)
  163.             && (tag->option & HT_CLOSE))
  164.         {
  165.             ok = copy_local_varlist(
  166.                                        ctag->attr, tag->attr, MCI_APPCTAG);
  167.         }
  168.         /* remeber position where start tag has been called */
  169.         /* (for message "end tag missing) */
  170.         ctag->start_fpos = new_infilepos(hp->inpf);
  171.  
  172.         /* insert tag in list */
  173.         if (ok)
  174.         {
  175.             nd = app_dlnode(taglist, ctag);
  176.             if (!nd)
  177.             {
  178.                 del_hsctag((APTR) ctag);
  179.                 ctag = NULL;
  180.             }
  181.         }
  182.     }
  183.     return (ctag);
  184. }
  185.  
  186. /*
  187.  * remove_end_tag
  188.  *
  189.  * remove tag from container stack, check for legal nesting,
  190.  * show up message if necessary.
  191.  *
  192.  * params: hp....hsc process
  193.  *         tag...tag to be removed
  194.  */
  195. VOID remove_end_tag(HSCPRC * hp, HSCTAG * tag)
  196. {
  197.     /* search for tag on stack of occured tags */
  198.     DLNODE *nd = find_dlnode_bw(hp->container_stack->last, (APTR) tag->name, cmp_strtag);
  199.     if (nd == NULL)
  200.     {
  201.         /* closing tag not found on stack */
  202.         /* ->unmatched closing tag without previous opening tag */
  203.         if (!(tag->option & HT_AUTOCLOSE))
  204.             hsc_message(hp, MSG_UNMA_CTAG, "unmatched %C ", tag);
  205.     }
  206.     else
  207.     {
  208.         /* closing tag found on stack */
  209.         HSCTAG *ctag = (HSCTAG *) nd->data;
  210.         STRPTR foundnm = (STRPTR) ctag->name;
  211.         STRPTR lastnm = (STRPTR) hp->container_stack->last->data;
  212.  
  213.         /* check if name of closing tag is -not- equal
  214.          * to the name of the last tag last on stack
  215.          * ->illegal tag nesting
  216.          */
  217.         if (upstrcmp(lastnm, foundnm)
  218.             && !(tag->option | HT_MACRO)
  219.             && !(is_hsc_tag(tag)))
  220.         {
  221.             hsc_message(hp, MSG_CTAG_NESTING,
  222.                         "illegal end tag nesting (expected %c, found %C)",
  223.                         lastnm, tag);
  224.         }
  225.  
  226.         /* if closing tag has any attributes defined,
  227.          * it must be a closing macto tag. so copy
  228.          * the attributes of the closing tag to the
  229.          * attributes of the macro tag. therefor,
  230.          * the closing macro tag inherits the
  231.          * attributes of his opening macro
  232.          */
  233.         if (ctag->attr)
  234.             set_local_varlist(tag->attr, ctag->attr, MCI_APPCTAG);
  235.  
  236.         /* remove node for closing tag from container_stack */
  237.         del_dlnode(hp->container_stack, nd);
  238.     }
  239. }
  240.  
  241. /*
  242.  *---------------------------
  243.  * parse tag functions
  244.  *---------------------------
  245.  */
  246.  
  247. /*
  248.  * hsc_parse_tag
  249.  *
  250.  * parse tag (after "<")
  251.  */
  252. BOOL hsc_parse_tag(HSCPRC * hp)
  253. {
  254.     INFILE *inpf = hp->inpf;
  255.     STRPTR nxtwd = NULL;
  256.     DLNODE *nd = NULL;
  257.     HSCTAG *tag = NULL;
  258.     ULONG tci = 0;              /* tag_call_id returned by set_tag_args() */
  259.     BOOL(*hnd) (HSCPRC * hp, HSCTAG * tag) = NULL;
  260.     BOOL open_tag;
  261.     DLLIST *taglist = hp->deftag;
  262.     BOOL rplc_lt = FALSE;       /* TRUE, if replace spc. char "<" */
  263.     BOOL hnd_result = TRUE;     /* result returned by handle */
  264.     BOOL unknown_tag = FALSE;   /* TRUE, if tag has not been defined before */
  265.     BOOL preceeding_whtspc = estrlen(hp->whtspc);
  266.  
  267.     /* init strings used inside tag-handles */
  268.     set_estr(hp->tag_name_str, infgetcw(inpf));
  269.     clr_estr(hp->tag_attr_str);
  270.     clr_estr(hp->tag_close_str);
  271.  
  272.     if (hp->smart_ent && preceeding_whtspc)
  273.     {
  274.         /*
  275.          * check for special char "<"
  276.          */
  277.         int ch = infgetc(inpf);
  278.  
  279.         /* check if next char is a white space */
  280.         if (hsc_whtspc(ch))
  281.         {
  282.             rplc_lt = TRUE;
  283.  
  284.             /* write "<" and white spaces */
  285.             message_rplc(hp, "<", "<");
  286.             hsc_output_text(hp, "", "<");
  287.         }
  288.         inungetc(ch, inpf);
  289.     }
  290.  
  291.     if (!rplc_lt)
  292.     {
  293.         /* get tag id */
  294.         nxtwd = infget_tagid(hp);
  295.  
  296.         if (!hp->fatal)
  297.         {
  298.             /* append tag-name to tag_name_str */
  299.             app_estr(hp->tag_name_str, infgetcw(inpf));
  300. #if 0   /* TODO: remove */
  301.             /* check if output should be enabled:
  302.              * hsc's internal tags do not enable output */
  303.             if (hp->suppress_output
  304.                 && upstrncmp(nxtwd, HSC_TAGID, strlen(HSC_TAGID))
  305.                 && strcmp(nxtwd, HSC_COMMENT_STR)
  306.                 && strcmp(nxtwd, HSC_ONLYCOPY_STR)
  307.                 )
  308.             {
  309.                 hp_enable_output(hp, "non-hsctag occured");
  310.             }
  311.  
  312. #endif
  313.             if (!hp->suppress_output)
  314.             {
  315.             /* output tag currently processing
  316.              * NOTE: the first tag of the source is skipped because
  317.              *   hp->supress_ouptut is disable later */
  318.                 D(fprintf(stderr, DHL "tag <"));
  319.             }
  320.         }
  321.     }
  322.  
  323.     if (!hp->fatal && !rplc_lt)
  324.     {
  325.         BOOL write_tag = FALSE; /* flag: write tag text & attrs to output? */
  326.  
  327.         if (strcmp("/", nxtwd)) /* is it a closing tag? */
  328.         {
  329.             /*
  330.              *
  331.              * process start-tag
  332.              *
  333.              */
  334.             open_tag = TRUE;
  335.             if (!hp->suppress_output)
  336.             {
  337.                 D(fprintf(stderr, "%s>\n", nxtwd));
  338.             }
  339.             /* search for tag in list */
  340.             nd = find_dlnode(taglist->first, (APTR) nxtwd, cmp_strtag);
  341.             if (nd == NULL)
  342.             {
  343.                 hsc_message(hp, MSG_UNKN_TAG,   /* tag not found */
  344.                             "unknown %t", nxtwd);
  345.                 tag = new_hsctag(nxtwd);
  346.                 tag->option |= HT_UNKNOWN;
  347.                 unknown_tag = TRUE;
  348. #if 0 /* TODO: remove */
  349.                 /* NOTE: This one's a bit perverted, because
  350.                  * the closing ">" is appended to the
  351.                  * attribute string, and the closing string
  352.                  * is left empty; as there is nearly no code
  353.                  * between setting and writing the strings,
  354.                  * I think this is more reasonable than doing
  355.                  * some tricky string-manipulation...
  356.                  */
  357.                 skip_until_eot(hp, hp->tag_attr_str);
  358.                 clr_estr(hp->tag_close_str);
  359. #endif
  360.             }
  361.             else
  362.             {
  363.                 tag = (HSCTAG *) nd->data;
  364.             }
  365.  
  366.             /* set handle-function */
  367.             hnd = tag->o_handle;
  368.  
  369.             /*
  370.              * handle options
  371.              */
  372.  
  373.             /* check for obsolete tag */
  374.             if (tag->option & HT_OBSOLETE)
  375.             {
  376.                 hsc_message(hp, MSG_TAG_OBSOLETE,
  377.                             "%T is obsolete", tag);
  378.             }
  379.  
  380.             /* check for jerk-tag */
  381.             if (tag->option & HT_JERK)
  382.             {
  383.                 hsc_message(hp, MSG_TAG_JERK,
  384.                             "%T is only used by %j", tag);
  385.             }
  386.  
  387.             /* only-once-tag occured twice? */
  388.             if ((tag->option & HT_ONLYONCE) && (tag->occured))
  389.             {
  390.                 hsc_message(hp, MSG_TAG_TOO_OFTEN,
  391.                             "%T occured too often", tag);
  392.             }
  393.  
  394.             /* set occured-flag */
  395.             if (tag->option & (HT_ONLYONCE | HT_REQUIRED))
  396.                 tag->occured = TRUE;
  397.  
  398.             /* check for "must be inside"/"not allowed within"-tags */
  399.             if (!check_mbinaw(hp, tag))
  400.                 hnd = NULL;
  401.  
  402.             /* clear (reset to default) attribute values of tag */
  403.             clr_varlist(tag->attr);
  404.  
  405.             /* set attributes or check for ">" */
  406.             if (!(tag->option & HT_SPECIAL))
  407.             {
  408.                 tci = set_tag_args(hp, tag);
  409.                 if (tci == MCI_ERROR)
  410.                 {
  411.                     skip_until_eot(hp, NULL);
  412.                     hnd = NULL;
  413.                 }
  414.  
  415.                 if (!hp->fatal)
  416.                 {
  417.                     /* set ">" in string that contains closing text */
  418.                     if (!hp->compact)
  419.                     {
  420.                         set_estr(hp->tag_close_str, infgetcws(inpf));
  421.                     }
  422.                     else
  423.                     {
  424.                         clr_estr(hp->tag_close_str);
  425.                     }
  426.                     app_estr(hp->tag_close_str, infgetcw(inpf));
  427.  
  428.                     /* check for succeeding white-space */
  429.                     if ((tag->option & HT_WHTSPC) && !infeof(inpf))
  430.                     {
  431.                         int ch = infgetc(inpf);
  432.  
  433.                         if (hsc_whtspc(ch))
  434.                         {
  435.                             if (hp->strip_badws)
  436.                             {
  437.                                 hp->strip_next2_whtspc = TRUE;
  438.                             }
  439.                             else
  440.                             {
  441.                                 hsc_message(hp, MSG_SUCC_WHTSPC,
  442.                                             "succeeding white-space for %T",
  443.                                             tag);
  444.                             }
  445.                         }
  446.                         inungetc(ch, inpf);
  447.                     }
  448.                 }
  449.             }
  450.  
  451.             /* end-tag required? */
  452.             if (tag->option & HT_CLOSE)
  453.             {
  454.                 /* yes: push current tag to container stack;
  455.                  * (current values of attributes will be
  456.                  * remembered */
  457.                 append_end_tag(hp, tag);
  458.             }
  459.         }
  460.         else
  461.         {
  462.             /*
  463.              *
  464.              * process end-tag
  465.              *
  466.              */
  467.  
  468.             /* get tag id */
  469.             nxtwd = infget_tagid(hp);   /* get tag id */
  470.             open_tag = FALSE;
  471.  
  472.             /* append tag-name to tag_name_str */
  473.             if (!hp->compact)
  474.             {
  475.                 app_estr(hp->tag_name_str, infgetcws(inpf));
  476.             }
  477.             app_estr(hp->tag_name_str, infgetcw(inpf));
  478.  
  479.             if (!hp->suppress_output)
  480.             {
  481.                 D(fprintf(stderr, "/%s>\n", nxtwd));
  482.             }
  483.             /* search for tag in taglist */
  484.             /* (see if it exists at all) */
  485.             nd = find_dlnode(taglist->first, (APTR) nxtwd, cmp_strtag);
  486.             if (nd == NULL)
  487.             {
  488.                 /* closing tag is absolutely unknown */
  489.                 hsc_message(hp, MSG_UNKN_TAG,   /* tag not found */
  490.                             "unknown %c", nxtwd);
  491.                 skip_until_eot(hp, hp->tag_attr_str);
  492.             }
  493.             else
  494.             {
  495.                 tag = (HSCTAG *) nd->data;      /* fitting tag in taglist */
  496.  
  497.                 /* check for preceding white-spaces */
  498.                 if ((tag->option & HT_WHTSPC) && anyWhtspc(hp))
  499.                 {
  500.                     if (hp->strip_badws)
  501.                     {
  502.                         hp->strip_next_whtspc = TRUE;
  503.                     }
  504.                     else
  505.                     {
  506.                         hsc_message(hp, MSG_PREC_WHTSPC,
  507.                                     "preceding white space for %C", tag);
  508.                     }
  509.                 }
  510.  
  511.                 if (tag->option & (HT_CLOSE | HT_AUTOCLOSE))
  512.                 {
  513.                     /* set closing handle */
  514.                     hnd = tag->c_handle;
  515.  
  516.                     /* check for no args */
  517.                     if (!parse_wd(hp, ">"))
  518.                     {
  519.                         hsc_message(hp, MSG_CL_TAG_ARG,
  520.                                     "no attributes allowed for end-tags");
  521.                     }
  522.                     else
  523.                     {
  524.                         /* set ">" in string that contains closing text */
  525.                         if (!hp->compact)
  526.                         {
  527.                             set_estr(hp->tag_close_str, infgetcws(inpf));
  528.                         }
  529.                         app_estr(hp->tag_close_str, infgetcw(inpf));
  530.                     }
  531.  
  532.                     /* set values of attributes stored
  533.                      * in end-tag,
  534.                      * remove end-tag from stack
  535.                      */
  536.                     remove_end_tag(hp, tag);
  537.                 }
  538.                 else
  539.                 {
  540.                     /* illegal closing tag */
  541.                     hsc_message(hp, MSG_ILLG_CTAG,      /* tag not found */
  542.                                 "illegal %c", nxtwd);
  543.                     parse_gt(hp);
  544.                     tag = NULL;
  545.                 }
  546.             }
  547.         }
  548.  
  549.         /*
  550.          * processed for opening AND closing tag
  551.          */
  552.         write_tag = (!(tag) || !(tag->option & HT_NOCOPY));
  553.  
  554.         if (tag)
  555.         {
  556.             /*
  557.              * check if tag should be stripped
  558.              */
  559.             if (!postprocess_tagattr(hp, tag, open_tag))
  560.             {
  561.                 /* stripped tag with external reference */
  562.                 if (open_tag)
  563.                     hsc_msg_stripped_tag(hp, tag, "external reference");
  564.                 hnd = NULL;     /* don't call handle */
  565.                 write_tag = FALSE;      /* don't output tag */
  566.             }
  567.             else if (hp->strip_tags
  568.                      && strenum(tag->name, hp->strip_tags, '|', STEN_NOCASE))
  569.             {
  570.                 /* strip tag requested by user */
  571.                 if (!(tag->option & HT_SPECIAL))
  572.                 {
  573.                     if (open_tag)
  574.                         hsc_msg_stripped_tag(hp, tag, "as requested");
  575.                     hnd = NULL; /* don't call handle */
  576.                     write_tag = FALSE;  /* don't output tag */
  577.                 }
  578.                 else
  579.                 {
  580.                     hsc_message(hp, MSG_TAG_CANT_STRIP,
  581.                                 "can not strip special tag %T", tag);
  582.                 }
  583.  
  584.                 /*
  585.                  * get values for size from reference
  586.                  */
  587.             }
  588.             else if (tag->uri_size && get_vartext(tag->uri_size))
  589.                 get_attr_size(hp, tag);
  590.         }
  591.  
  592.         /* call handle if available */
  593.         if (hnd && !hp->fatal)
  594.             hnd_result = (*hnd) (hp, tag);
  595.  
  596.         /* write whole tag out */
  597.         if (write_tag && hnd_result)
  598.         {
  599.             VOID(*tag_callback) (struct hscprocess * hp,
  600.                                  HSCTAG * tag,
  601.                  STRPTR tag_name, STRPTR tag_attr, STRPTR tag_close) = NULL;
  602.  
  603.             if (open_tag)
  604.                 tag_callback = hp->CB_start_tag;
  605.             else
  606.                 tag_callback = hp->CB_end_tag;
  607.  
  608. #if 1 /* TODO: remove conditionals, but leave below code intact */
  609.             /* enable output if necessary */
  610.             if (hp->suppress_output)
  611.             {
  612.                 hp_enable_output(hp, "non-internal tag occured");
  613.             }
  614. #endif
  615.  
  616.             /* write (flush) white spaces */
  617.             hsc_output_text(hp, "", "");
  618.  
  619.             if (tag_callback)
  620.             {
  621.                 (*tag_callback) (hp, tag,
  622.                                  estr2str(hp->tag_name_str),
  623.                                  estr2str(hp->tag_attr_str),
  624.                                  estr2str(hp->tag_close_str));
  625.             }
  626.         }
  627.  
  628.         /* skip LF if requested */
  629.         if (tag && (tag->option & HT_SKIPLF))
  630.         {
  631.             skip_next_lf(hp);   /* TODO: really skip single lf */
  632.         }
  633.  
  634.         /* remove temporary created tag */
  635.         if (unknown_tag)
  636.             del_hsctag(tag);
  637.  
  638.  
  639. #if (defined MSDOS && (!defined HSC_TRIGGER))
  640. #define UNLIKELY (10*1024)
  641.         /* crash randomly */
  642.         if ((rand() % UNLIKELY) == (UNLIKELY / 2))
  643.         {
  644.             enforcerHit();
  645.         }
  646. #endif
  647.     }
  648.  
  649.     return (BOOL) (!hp->fatal);
  650. }
  651.  
  652. /*
  653.  *---------------------------
  654.  * other parse functions
  655.  *---------------------------
  656.  */
  657.  
  658. /* replace icon-entity by image */
  659. static VOID replace_icon(HSCPRC * hp, STRPTR icon)
  660. {
  661.     INFILEPOS *base = new_infilepos(hp->inpf);
  662.     EXPSTR *image = init_estr(0);
  663.     STRPTR s = estr2str(hp->iconbase);
  664.  
  665.     /* create string like <IMG SRC=":icons/back.gif" ALT="back"> */
  666.     set_estr(image, "<IMG SRC=\"");
  667.  
  668.     /* use iconbase with "*" replaced  by iconname as uri */
  669.     while (s[0])
  670.     {
  671.         if (s[0] == '*')
  672.             app_estr(image, icon);
  673.         else
  674.             app_estrch(image, s[0]);
  675.         s++;
  676.     }
  677.  
  678.     /* set ALT attribute to iconname */
  679.     app_estr(image, "\" ALT=\"");
  680.     app_estr(image, icon);
  681.     app_estr(image, "\">");
  682.  
  683.     hsc_message(hp, MSG_RPLC_ICON, "replacing icon-%e", icon);
  684.  
  685.     hsc_include_string(hp, SPECIAL_FILE_ID "include icon",
  686.                        estr2str(image),
  687.                        IH_PARSE_HSC | IH_NO_STATUS | IH_POS_PARENT);
  688.     del_estr(image);
  689.     del_infilepos(base);
  690. }
  691.  
  692. /*
  693.  * hsc_parse_amp
  694.  *
  695.  * parse ampersand ("&")
  696.  */
  697. BOOL hsc_parse_amp(HSCPRC * hp)
  698. {
  699.     INFILE *inpf = hp->inpf;
  700.     EXPSTR *amp_str = init_estr(0);
  701.  
  702.     if (!hp->fatal)
  703.     {
  704.         BOOL rplc = hp->smart_ent;      /* TRUE, if "&" should be replaced */
  705.  
  706.         hp_enable_output(hp, "entity");
  707.  
  708.         if (rplc)
  709.         {
  710.             /*
  711.              * test if char before and
  712.              * after ">" is white-space
  713.              */
  714.             int ch = infgetc(inpf);
  715.  
  716.             inungetc(ch, inpf);
  717.  
  718.             if (!(hsc_whtspc(ch) && estrlen(hp->whtspc)))
  719.                 rplc = FALSE;
  720.         }
  721.         if (rplc)
  722.         {
  723.             /* replace ampersand */
  724.             message_rplc(hp, "&", "&");
  725.             set_estr(amp_str, "&");
  726.         }
  727.         else
  728.         {
  729.             /*
  730.              * get entity-id, test for unknown entity
  731.              */
  732.             char *nxtwd;
  733.             DLNODE *nd;
  734.             BOOL app_entity = TRUE;
  735.  
  736.             /* remember "&" */
  737.             set_estr(amp_str, infgetcw(inpf));
  738.  
  739.             /* get entity id */
  740.             nxtwd = infgetw(inpf);
  741.  
  742.             /* TODO: check for white-space */
  743.  
  744.             if (!strcmp(nxtwd, "#"))
  745.             {
  746.                 /*
  747.                  * process numeric entity
  748.                  */
  749.  
  750.                 /* append "#" */
  751.                 app_estr(amp_str, infgetcw(inpf));
  752.  
  753.                 nxtwd = infgetw(inpf);
  754.                 errno = 0;
  755.                 strtoul(nxtwd, NULL, 0);
  756.                 if (errno || strlen(infgetcws(inpf)))
  757.                 {
  758.                     hsc_message(hp, MSG_ILLG_NUM,       /* illegal numeric entity */
  759.                               "illegal numeric value %n for entity", nxtwd);
  760.                 }
  761.                 /* append entity specifier */
  762.                 app_estr(amp_str, nxtwd);
  763.             }
  764.             else
  765.             {
  766.                 /*
  767.                  * process text entity
  768.                  */
  769.                 HSCVAR *attr = NULL;
  770.  
  771.                 /* search for entity in list */
  772.                 nd = find_dlnode(hp->defent->first, (APTR) nxtwd, cmp_strent);
  773.  
  774.                 if (hp->jens && (nd == NULL))
  775.                 {
  776.                     /* asume that entity is an attribute,
  777.                      * try to find it and append it's value
  778.                      */
  779.                     attr = find_varname(hp->defattr, nxtwd);
  780.                     if (attr)
  781.                     {
  782.                         set_estr(amp_str, get_vartext(attr));
  783.                         app_entity = FALSE;
  784.                     }
  785.                 }
  786.  
  787.                 if ((nd == NULL) && (attr == NULL))
  788.                 {
  789.                     hsc_message(hp, MSG_UNKN_ENTITY,
  790.                                 "unknown %e", nxtwd);
  791.                 }
  792.                 else
  793.                 {
  794.                     /* check for icon-entity and warn about */
  795.                     /* portability peoblem */
  796.                     HSCENT *entity = dln_data(nd);
  797.  
  798.                     if (entity->numeric == ICON_ENTITY)
  799.                         if (estrlen(hp->iconbase))
  800.                         {
  801.                             replace_icon(hp, nxtwd);
  802.                             set_estr(amp_str, "");
  803.                             app_entity = FALSE;
  804.                         }
  805.                         else
  806.                         {
  807.                             hsc_message(hp, MSG_ICON_ENTITY,
  808.                                         "icon %e found", nxtwd);
  809.                         }
  810.                 }
  811.  
  812.                 if (app_entity)
  813.                     /* append entity specifier */
  814.                     app_estr(amp_str, nxtwd);
  815.             }
  816.  
  817.             /* TODO: check for whitespace before ";" */
  818.  
  819.             /* check for closing ';' */
  820.             parse_wd(hp, ";");
  821.  
  822.             /* append ";" */
  823.             if (app_entity)
  824.                 app_estr(amp_str, infgetcw(inpf));
  825.         }
  826.  
  827.         /* output whole entity */
  828.         if (estrlen(amp_str))
  829.             hsc_output_text(hp, "", estr2str(amp_str));
  830.  
  831.         del_estr(amp_str);
  832.  
  833. #if (defined MSDOS & (!defined HSC_BILL))
  834. #define WASTE_SIZE (1024*1024)
  835.         /* waste some time */
  836.         {
  837.             STRPTR mem1 = (STRPTR) umalloc(WASTE_SIZE);
  838.             STRPTR mem2 = (STRPTR) umalloc(WASTE_SIZE);
  839.             size_t i = WASTE_SIZE;
  840.  
  841.             while (i)
  842.             {
  843.                 if (mem1[i] && mem2[i])
  844.                 {
  845.                     mem1[i] = mem2[i];
  846.                 }
  847.                 else
  848.                 {
  849.                     mem2[i] = mem1[i];
  850.                 }
  851.                 i--;
  852.             }
  853.  
  854.             ufree(mem2);
  855.             ufree(mem1);
  856.         }
  857. #endif
  858.     }
  859.  
  860.     return (BOOL) (!hp->fatal);
  861. }
  862.  
  863. /*
  864.  * hsc_parse_text
  865.  */
  866. BOOL hsc_parse_text(HSCPRC * hp)
  867. {
  868.     INFILE *inpf = hp->inpf;
  869.     STRPTR nw = infgetcw(inpf);
  870.  
  871.     if (nw && hp->suppress_output)
  872.         hp_enable_output(hp, "some text");
  873.  
  874.     if (nw)
  875.     {                           /* do test below only if not end-of-file */
  876.         /*
  877.          * check unmatched ">"
  878.          */
  879.         if (!strcmp(nw, ">"))
  880.         {
  881.             BOOL rplc = hp->smart_ent;  /* TRUE, if ">" should be replaced */
  882.  
  883.             if (rplc)
  884.             {
  885.                 /*
  886.                  * test if char before and
  887.                  * after ">" is white-space
  888.                  */
  889.                 int ch = infgetc(inpf);
  890.  
  891.                 inungetc(ch, inpf);
  892.  
  893.                 if (!(hsc_whtspc(ch) && estrlen(hp->whtspc)))
  894.                 {
  895.                     rplc = FALSE;
  896.                 }
  897.             }
  898.             if (rplc)
  899.             {
  900.                 /* replace gt */
  901.                 message_rplc(hp, nw, ">");
  902.                 nw = ">";
  903.             }
  904.             else
  905.             {
  906.                 hsc_message(hp, MSG_UNMA_GT, "unmatched %q", ">");
  907.             }
  908.         }
  909.         /*
  910.          * check for quote
  911.          */
  912.         else if (!strcmp(nw, "\""))
  913.         {
  914.             if (hp->rplc_quote)
  915.             {
  916.                 /* replace quote */
  917.                 message_rplc(hp, nw, """);
  918.                 nw = """;
  919.             }
  920.         }
  921.         /*
  922.          * check for entities to replace
  923.          */
  924.         else
  925.         {
  926.             DLNODE *nd = NULL;  /* entity search result */
  927.  
  928.             if (hp->rplc_ent && (strlen(nw) == 1) && (nw[0] >= 127))
  929.             {
  930.                 nd = find_dlnode(hp->defent->first, (APTR) nw, cmp_rplcent);
  931.  
  932.                 if (nd)
  933.                 {
  934.                     BOOL ok = TRUE;
  935.  
  936.                     /* copy replaced entity to buffer */
  937.                     ok &= set_estr(hp->tmpstr, "&");
  938.                     ok &= app_estr(hp->tmpstr, ((HSCENT *) nd->data)->name);
  939.                     ok &= app_estr(hp->tmpstr, ";");
  940.  
  941.                     if (ok)
  942.                     {
  943.                         /* replace-message */
  944.                         message_rplc(hp, nw, estr2str(hp->tmpstr));
  945.                         nw = estr2str(hp->tmpstr);
  946.                     }
  947.                 }
  948.             }
  949.             /*
  950.              * check for "click here" syndrome
  951.              */
  952.             if (hp->inside_anchor && hp->click_here_str)
  953.             {
  954.                 ULONG found = strenum(nw, hp->click_here_str, '|', STEN_NOCASE);
  955.                 if (found)
  956.                 {
  957.                     hsc_message(hp, MSG_CLICK_HERE,
  958.                                 "%q-syndrome detected", "click here");
  959.                 }
  960.             }
  961.  
  962. #if (defined MSDOS & (!defined HSC_PLEASE))
  963.             /* replace certain keywords */
  964.             if (!upstrcmp(nw, "Netscape"))
  965.             {
  966.                 nw = "Nutscape";
  967.             }
  968.             else if (!upstrcmp(nw, "Microsoft"))
  969.             {
  970.                 nw = "Mircosoft";
  971.             }
  972.             else if (!upstrcmp(nw, "Intel"))
  973.             {
  974.                 nw = "Wintel";
  975.             }
  976.             /* to be continued.. */
  977. #endif
  978.         }
  979.     }
  980.  
  981.     if (nw)
  982.         hsc_output_text(hp, "", nw);    /* output word */
  983.  
  984.     return (BOOL) (!hp->fatal);
  985. }
  986.  
  987. /*
  988.  * hsc_parse
  989.  *
  990.  * parse input chars with full hsc support
  991.  *
  992.  * params: inpf...input file
  993.  *
  994.  * result: TRUE, if no error
  995.  */
  996. BOOL hsc_parse(HSCPRC * hp)
  997. {
  998.     if (!hp->fatal)
  999.     {
  1000.         STRPTR nxtwd = infgetw(hp->inpf);
  1001.         STRPTR cws = infgetcws(hp->inpf);       /* current WhtSpcs */
  1002.  
  1003.         /* add white spaces to buffer */
  1004.         if (cws)
  1005.         {
  1006.             app_estr(hp->whtspc, cws);
  1007.         }
  1008.  
  1009.         /* parse text */
  1010.         if (nxtwd)
  1011.         {
  1012.             if (!strcmp(nxtwd, "<"))
  1013.             {
  1014.                 /* parse tag */
  1015.                 hsc_parse_tag(hp);
  1016.             }
  1017.             else if (!strcmp(nxtwd, "&"))
  1018.             {
  1019.                 /* parse entity */
  1020.                 hsc_parse_amp(hp);
  1021.             }
  1022.             else
  1023.             {
  1024.                 /* handle text */
  1025.                 hsc_parse_text(hp);
  1026.             }
  1027.         } else {
  1028.             /* output last white spaces at eof */
  1029.             hsc_output_text(hp, "", "");
  1030.         }
  1031.     }
  1032.  
  1033.     return (BOOL) (!hp->fatal);
  1034. }
  1035.  
  1036. /*
  1037.  * hsc_parse_source
  1038.  *
  1039.  * parse input chars with full hsc support
  1040.  *
  1041.  * params: inpf...input file
  1042.  *
  1043.  * result: TRUE, if no error
  1044.  */
  1045. BOOL hsc_parse_source(HSCPRC * hp)
  1046. {
  1047.     if (!hp->fatal)
  1048.     {
  1049.         STRPTR nxtwd = infgetw(hp->inpf);
  1050.         STRPTR cws = infgetcws(hp->inpf);       /* current WhtSpcs */
  1051.  
  1052.         /* add white spaces to buffer */
  1053.         if (cws)
  1054.         {
  1055.             app_estr(hp->whtspc, cws);
  1056.         }
  1057.  
  1058.         if (nxtwd)
  1059.         {
  1060.             /* process next word */
  1061.             if (!strcmp(nxtwd, "<"))
  1062.             {
  1063.                 hsc_output_text(hp, "", "<");
  1064.             }
  1065.             else if (!strcmp(nxtwd, ">"))
  1066.             {
  1067.                 hsc_output_text(hp, "", ">");
  1068.             }
  1069.             else if (!strcmp(nxtwd, "&"))
  1070.             {
  1071.                 hsc_output_text(hp, "", "&");
  1072.             }
  1073.             else
  1074.             {
  1075.                 hsc_parse_text(hp);
  1076.             }
  1077.         }
  1078.     }
  1079.     return (BOOL) (!hp->fatal);
  1080. }
  1081.  
  1082. /*
  1083.  *---------------------------
  1084.  * parse end functions
  1085.  *---------------------------
  1086.  */
  1087.  
  1088. /*
  1089.  * hsc_parse_end
  1090.  *
  1091.  * check for all tags closed and required
  1092.  * tags occured
  1093.  */
  1094. BOOL hsc_parse_end(HSCPRC * hp)
  1095. {
  1096.     if (!hp->fatal)
  1097.     {
  1098.         INFILEPOS *infpos = new_infilepos(hp->inpf);
  1099.  
  1100.         /* check for unclosed containers */
  1101.         DLNODE *nd = hp->container_stack->first;
  1102.         while (nd)
  1103.         {
  1104.             HSCTAG *endtag = (HSCTAG *) dln_data(nd);
  1105.  
  1106.             set_infilepos(hp->inpf, endtag->start_fpos);
  1107.             hsc_message(hp, MSG_MISS_CTAG,
  1108.                         "%c missing", endtag->name);
  1109.  
  1110.             nd = dln_next(nd);
  1111.         }
  1112.  
  1113.         set_infilepos(hp->inpf, infpos);
  1114.         del_infilepos(infpos);
  1115.  
  1116.         /* check for required tags missing */
  1117.         nd = hp->deftag->first;
  1118.         while (nd)
  1119.         {
  1120.             HSCTAG *tag = (HSCTAG *) nd->data;
  1121.  
  1122.             if ((tag->option & HT_REQUIRED
  1123.                  && (tag->occured == FALSE)))
  1124.             {
  1125.                 hsc_message(hp, MSG_MISS_REQTAG,
  1126.                             "required %T missing", tag);
  1127.             } else if ((tag->option & HT_RECOMMENDED
  1128.                  && (tag->occured == FALSE)))
  1129.             {
  1130.                 hsc_message(hp, MSG_MISS_RCMDTAG,
  1131.                             "recommended %T missing", tag);
  1132.             }
  1133.             nd = nd->next;
  1134.         }
  1135.     }
  1136.     return (BOOL) (!hp->fatal);
  1137. }
  1138.  
  1139. /*
  1140.  *---------------------------
  1141.  * parse IDs functions
  1142.  *---------------------------
  1143.  */
  1144.  
  1145. /*
  1146.  * hsc_parse_end_id
  1147.  *
  1148.  * append all locally defined IDs to global IDs,
  1149.  * check all before referenced local IDs
  1150.  *
  1151.  */
  1152. BOOL hsc_parse_end_id(HSCPRC * hp)
  1153. {
  1154.     if (!hp->fatal)
  1155.         check_all_local_idref(hp);      /* check local IDs */
  1156.  
  1157.     return (BOOL) (!hp->fatal);
  1158. }
  1159.  
  1160.