home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / txict100.zip / texicvt1.00 / source / utilhtml.cc < prev    next >
C/C++ Source or Header  |  1997-03-31  |  22KB  |  851 lines

  1. /*
  2. ================================================================================
  3.                         Texinfo converting Tools
  4.                          Release 1.00 28.03.97
  5.                        (c) 1996 by Andreas Kaiser
  6.                     (c) 1997 by Karl Heinz Marbaise
  7. ================================================================================
  8.  
  9. Discription:
  10.     Utils for conversion from Texinfo to HTML
  11.  
  12. Authors:
  13.    Andreas Kaiser
  14.    Karl Heinz Marbaise
  15.  
  16. e-mail:
  17.    Internet: KHMarbaise@p69.ks.fido.de
  18.    Fido-net: 2:2452/117.69
  19.  
  20. Bugs, question:
  21.    to above e-mail adress.
  22.  
  23. Register:
  24.    Please send a e-mail to above adress to register.
  25.    (include the release you want to register)
  26.    This registration should be done to let me
  27.    know how many people using these tools and
  28.    if it is worth to invest more time in continuing
  29.    development these tools or let the first release
  30.    of them be the last.
  31.    That is the only reason to make a registration.
  32.    I think a e-mail is not to much, isn't it?
  33.  
  34. License:
  35.    The "Texinfo converting tools" are free software;
  36.    you can redistribute it and/or modify it under the terms of
  37.    the GNU General Public License as published by the Free
  38.    Software Foundation; either version 2, or (at your option)
  39.    any later version.
  40.  
  41.    The "Texinfo converting tools" are distributed in the hope that
  42.    they will be useful, but WITHOUT ANY WARRANTY; without even the
  43.    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  44.    PURPOSE.  See the GNU General Public License for more details.
  45.  
  46.    You should have received a copy of the GNU General Public License
  47.    along with the "Texinfo converting tools" ; see the file COPYING.
  48.    If not, write to the:
  49.    Free Software Foundation,
  50.    59 Temple Place - Suite 330,
  51.    Boston, MA 02111-1307, USA.
  52.  
  53.    See \texicvt1.00\COPYING for details.
  54.  
  55. ================================================================================
  56. */
  57.  
  58.  
  59. /*
  60. ------------------------------------------------------------------------------
  61.                       (R)evision (C)ontrol (S)ystem
  62. ------------------------------------------------------------------------------
  63. */
  64.  
  65. #ifdef __RCS__
  66. static const char *utilhtml_cc = "$Id: UTILHTML.CC 1.3 1997/03/30 15:08:23 KHM Exp $";
  67. #endif
  68.  
  69. #include "info.h"
  70. #include <ctype.h>
  71. #include <alloca.h>
  72. #include <limits.h>
  73. #include <minmax.h>
  74.  
  75. static char *    old_font = "default";
  76. static int    preface  = 1;
  77.  
  78. ////////////////////////////////////////////////////////////////////////
  79.  
  80. static const char *fstack[10] = {"default"};
  81. static int       fstackx    = 0;
  82.  
  83. void
  84. font(const char *name, const char *size)
  85. {
  86.     if (!name)
  87.         name = fstack[fstackx];
  88.     if (strcmp(name, "default") == 0) {
  89.         PUTA(":font facename=default size=0x0.");
  90.     } else
  91.         PUTA(":font facename=" << name << " size=" << size << '.');
  92. }
  93.  
  94. void
  95. beg_example(const char *fontname)
  96. {
  97.     newpara = 0;
  98.     ++nofill;
  99.     *out << "<PRE>"; /*<< endl;*/
  100.     /*margin(+10);*/
  101.     fstack[++fstackx] = fontname;
  102.     /*font(0);*/
  103.     PUTL();
  104.     newpara = 0;
  105. }
  106.  
  107. void
  108. end_example()
  109. {
  110.     newpara = 0;
  111.     --nofill;
  112.     --fstackx;
  113.     /*font(0);*/
  114.     /*margin(-10);*/
  115.     *out << "</PRE>";
  116.     PUTL();
  117.     newpara = 0;
  118. }
  119.  
  120. ////////////////////////////////////////////////////////////////////////
  121.  
  122. void
  123. words(String& line)
  124. {
  125.     int i = 0;
  126.     String tmp;
  127.     int pos;
  128.     for (const char *p1 = line.chars(), *end = p1 + line.length();;) {
  129.         while (p1 < end && isspace(*p1))
  130.             ++p1;
  131.         if (p1 == end)
  132.             break;
  133.         const char *p2 = p1;
  134.         while (p2 < end && *p2 != ',')
  135.             ++p2;
  136.         if (i < MaxW)
  137.         {
  138.             tmp = String (p1, p2 - p1);
  139.             if (tmp.length ())
  140.             {
  141.             pos = tmp.length ()-1;
  142.  
  143.                 while (tmp.length () && (isspace(tmp[pos]) || tmp[pos] == '\t'))
  144.                 tmp.del (pos--,1);
  145.             }
  146.             w[i++] = tmp;
  147.         }
  148.         if (p2 == end)
  149.             break;
  150.         p1 = p2 + 1;
  151.     }
  152.     while (i < MaxW)
  153.         w[i++] = null;
  154. }
  155.  
  156. void
  157. spaced(String& line)
  158. {
  159.     int i = 0;
  160.     for (const char *p1 = line.chars(), *end = p1 + line.length();;) {
  161.         while (p1 < end && isspace(*p1))
  162.             ++p1;
  163.         if (p1 == end)
  164.             break;
  165.         const char *p2 = p1;
  166.         while (p2 < end && !isspace(*p2))
  167.             ++p2;
  168.         if (i < MaxW)
  169.             w[i++] = String(p1, p2 - p1);
  170.         if (p2 == end)
  171.             break;
  172.         p1 = p2 + 1;
  173.     }
  174.     while (i < MaxW)
  175.         w[i++] = null;
  176. }
  177.  
  178. ////////////////////////////////////////////////////////////////////////
  179.  
  180. static int    hstack[6];
  181. static int    hlevel = 0;
  182.  
  183. void
  184. heading(int level, const char *s)
  185. {
  186.         if (debug)
  187.             cerr << "Heading:: " << s << endl;
  188.     if (istackp != istack)
  189.         return;
  190.     if (f_node) {
  191.         if (preface)
  192.             PUT(":h2." << s << endl << ":lm margin=1.");
  193.     } else {
  194.         if (debug)
  195.             cerr << "Heading, logical level=" << level
  196.                  << " stack level=" << hlevel
  197.                  << " stacked=" << hstack[hlevel];
  198.         if (level > hstack[hlevel])
  199.             hstack[++hlevel] = level;
  200.         else while (level < hstack[hlevel])
  201.             --hlevel;
  202.         if (debug)
  203.             cerr << " panel level=" << hlevel << endl;
  204.         if (node_id) {
  205.             panel_id = node_id;
  206.             node_id = 0;
  207.         } else
  208.             panel_id = ++hdid;
  209.         panel_name = s;
  210.                 *out << "<H" << hlevel << ">"
  211.                      << "<A NAME=\"hd_" << panel_id << "\">"
  212.                      << s << "</A></H" << hlevel << ">" << endl;
  213.                 /* Bisher: PUT("<H" << hlevel << ">" << s << "</H" << hlevel << ">" << endl); */
  214.         /*PUT(":h" << hlevel << " id=hd" << panel_id << '.' << s
  215.              << endl << ":lm margin=1.");*/
  216.     }
  217. }
  218.  
  219.  
  220. void Menu::flush()
  221. {
  222.     int x1;
  223.     int x2;
  224.     String name;
  225.     String Node;
  226.     String Filename;
  227.     String Text;
  228.  
  229.     if (!line.length())
  230.         return;
  231.  
  232.     x1 = line.index(":");
  233.     if (debug)
  234.         cerr << "Menu::flush ()" << endl
  235.              << "    line=\"" << line << "\"" << endl;
  236.  
  237.  
  238.     if (x1>=0)
  239.     {
  240.         x2 = line.index (":", x1+1);
  241.         /* Is this a menu entry like:
  242.            * Node::   discription
  243.          */
  244.         if (x2 > 0)
  245.         {
  246.             /* Yes it is. */
  247.             if ((x2-x1) == 1)
  248.                 name = line.before (x1);
  249.             else
  250.                 cerr << "Menu::flush ()" << endl
  251.                      << "    the second colon is not positioned after the first!" << endl;
  252.  
  253.             if (!table.contains(name))
  254.                 table[name] = Name(++hdid);
  255.  
  256.             for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
  257.                 ;
  258.  
  259.             Node = line.before (x1);
  260.             Text = line.from (x2);
  261.             if (!Text.length ())
  262.                 Text = Node;
  263.  
  264.             *out << "<LI><A HREF=\"#"
  265.                  << Node << "\">"
  266.                  << Text << "</A>"
  267.                  << endl;
  268.  
  269.         }
  270.         else
  271.         {
  272.             /* If we came here it might be an
  273.              * entry like this:
  274.                  * Entry: node-name.   Discription
  275.              */
  276.             /* search the positition of the dot */
  277.             x2 = line.index (".", x1+1);
  278.  
  279.             for (x1 += 1; x1 < line.length() && isspace(line[x1]); ++x1)
  280.                 ;
  281.             name = line.at (x1, x2-x1);
  282.  
  283.             for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
  284.                 ;
  285.  
  286.             /* check if a file name is part of the node */
  287.             if (name.index("(", 1) == 1)
  288.             {
  289.                 /* extract the file name */
  290.                 Filename = name.at (name.index("(",1), name.index (")", 2));
  291.                 while (name[0]!=')' && name.length ())
  292.                     name.del(0,1);
  293.             }
  294.             else
  295.                 Filename = "";
  296.  
  297.             if (Filename.length())
  298.             {
  299.                 /* Node out of another file */
  300.                 cerr << "Menu::line ()" << endl
  301.                      << "  actualy we don't support this" << endl;
  302.             }
  303.             else
  304.             {
  305.             }
  306.  
  307.                 Text =  line.from (x2);
  308.                 if (!Text.length ())
  309.                     Text = name;
  310.  
  311.                 if (!table.contains(name))
  312.                     table[name] = Name(++hdid);
  313.                 *out << "<LI><A HREF=\"#" << name << "\">"
  314.                      << Text << "</A>"
  315.                      << endl;
  316.  
  317.             if (debug)
  318.                 cerr << "*** Node=\"" << name << "\"" << endl
  319.                      << "    Text=\"" << Text << "\"" << endl
  320.                      << "    File=\"" << Filename << "\"" << endl;
  321.         }
  322.     } /* if (x1>=0)... */
  323.  
  324.  
  325.     /**************************************
  326.     if (x1 >= 0) {
  327.         int x2 = line.index(":", x1+1);
  328.         if (x2 >= 0) {
  329.             String name = line.at(x1+1, x2-x1-1);
  330.             if (name.length() == 0)
  331.                 name = line.before(x1);
  332.             if (!table.contains(name))
  333.                 table[name] = Name(++hdid);
  334.             for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
  335.                 ;
  336.  
  337.                         *out << "<LI><A HREF=\"#"
  338.                              << line.before(x1)
  339.                              << "\">"
  340.                              << line.from(x2) << "</A>"
  341.                              << endl;
  342.         }
  343.     } **********************************/
  344.     line = "";
  345. }
  346.  
  347. void
  348. node(String name, String next, String prev, String up)
  349. {
  350.         if (debug)
  351.             cerr << "node:: " << name << "," << next << "," << prev << "," << up << endl;
  352.  
  353.     if (table.contains(up)) {
  354.         if (f_node)
  355.             hlevel = table[up].level + 1;
  356.     } else if (name == "Top" || up.length() == 0) {
  357.         if (f_node)
  358.             hlevel = 0;
  359.     } else {
  360.         cerr << "<up> node undefined in '" << name << "', '" << next
  361.             << "', '" << prev << "', '" << up << '\'' << endl;
  362.         cerr.flush();
  363. #if 0
  364.         exit(1);
  365. #endif
  366.     }
  367.     if (debug)
  368.         cerr << "Define name='" << name << "' next='" << next
  369.              << "' prev='" << prev << "' up='" << up << "'";
  370.     Name& entry = table[name];
  371.     if (entry.id) {
  372.         if (entry.defined) {
  373.             cerr << "Node '" << name << "' redefined " << endl;
  374.             cerr.flush();
  375. #if 0
  376.             exit(1);
  377. #endif
  378.         }
  379.         entry.defined = 1;
  380.         if (debug)
  381.             cerr << ", known id=" << entry.id << endl;
  382.     } else {
  383.         table[name] = Name(++hdid, 1, hlevel);
  384.         if (debug)
  385.             cerr << ", new id=" << hdid << endl;
  386.     }
  387.  
  388.         if (debug)
  389.             cerr << "node:: " << name << "," << next << "," << prev << "," << up << " hlevel=" << hlevel << endl;
  390.  
  391.     /*if (f_node && hlevel >= 1 && hlevel <= 6 && istackp == istack) {*/
  392.     if (hlevel >= 0 && hlevel <= 6 ) {
  393.         preface = 0;
  394.         if (debug)
  395.                     cerr << "<A NAME=\"" << name << "\"></A>" << endl;
  396.                 *out << "<A NAME=\"" << name << "\"></A>" << endl;
  397.         /* PUT(":h" << hlevel << " id=hd" << entry.id << '.' << name
  398.              << endl << ":lm margin=1."); */
  399.     }
  400.     node_name = name;
  401.     node_id = entry.id;
  402. }
  403.  
  404. void
  405. xref(char *see, String name, String entry, String topic, String file, String manual)
  406. {
  407.     if (debug)
  408.         cerr << "Refer to name='" << name << "' entry='" << entry
  409.              << "' topic='" << topic << "' file='" << file
  410.              << "' manual='" << manual << "'";
  411.     if (see)
  412.         PUTS(see);
  413.     if (file.empty()) {
  414.         if (!table.contains(name)) {
  415.             table[name] = Name(++hdid);
  416.             if (debug)
  417.                 cerr << " new id=" << hdid << endl;
  418.         } else
  419.             if (debug)
  420.                 cerr << " known id=" << table[name].id << endl;
  421.                 *out << "<A HREF=\"#" << name << "\">";
  422.         /*PUTS(":link reftype=hd refid=hd" << table[name].id << '.');*/
  423.         if (topic.length()) {
  424.             /*PUT(topic);*/ *out << topic;
  425.         } else
  426.             /*PUT(name);*/ *out << name;
  427.         if (entry.length())
  428.                     *out << " <I>" << entry << "</I>";
  429.             /*PUT(": " << entry);*/
  430.         *out << "</A>";/*PUT(":elink.");*/
  431.     } else
  432.                 *out << "Section " << topic << " of <H3>" << manual << "</H3>";
  433.         /*PUTS("Section " << topic << " of :hp1." << manual << ":ehp1.");*/
  434. }
  435.  
  436. ////////////////////////////////////////////////////////////////////////
  437.  
  438. static int current_margin = 0;
  439.  
  440. static void
  441. set_margin(int indent)
  442. {
  443.     current_margin = indent;
  444.     /*PUTA(":lm margin=" << (1 + current_margin) << '.');*/
  445. }
  446.  
  447.     // > 0: indent
  448.     // < 0: extend
  449.     // = 0: reset
  450. int
  451. margin(int delta)
  452. {
  453.     int old = current_margin;
  454.     if (delta) {
  455.         current_margin += delta;
  456.         if (current_margin < 0)
  457.             current_margin = 0;
  458.     } else
  459.         current_margin = 0;
  460.     /*PUTA(":lm margin=" << (1 + current_margin) << '.');*/
  461.     return old;
  462. }
  463.  
  464. void
  465. item_begin(const char *text, int it, char *ic)
  466. {
  467.     if (istackp == istack) {
  468.         istackp->indent = current_margin;
  469.         istackp->nested = 1;
  470.     }
  471.     ++istackp;
  472.     istackp->type = it;
  473.     istackp->cat = ic;
  474.     istackp->beg = Item();
  475.     istackp->end = Item();
  476.     istackp->indent = current_margin;
  477.     switch (it) {
  478.     case 'o':
  479.         istackp->indent += 3;
  480.         break;
  481.     case 'u':
  482.         istackp->indent += 5;
  483.         break;
  484.     case 'p':
  485.         istackp->indent += 12;
  486.         break;
  487.     }
  488.     istackp->nested = 0;
  489.     istackp->count = 0;
  490.     for (ItemType *p = istack; p < istackp; ++p)
  491.         if (p->type == 'p')
  492.             ++istackp->nested;
  493.     /*PUTL();*/
  494.     /*if (!istackp->nested) */
  495.         PUT (text);
  496.         /* PUT(text);*/
  497.     newpara = 0;
  498. }
  499.  
  500. void
  501. ItemType::item(const char *text)
  502. {
  503.     newpara = 0;
  504.         if (debug)
  505.             cerr << "ItemType::item (): \"" << text << "\"" << endl;
  506.  
  507.     if (nested) {
  508.         set_margin((istackp-1)->indent);
  509.         /* *out << ":p.";*/
  510.                 *out << "<DT>";
  511.         switch (type) {
  512.         case 'o':
  513.             margin(+1);
  514.             *out << ".&larrow.";
  515.             margin(+2);
  516.             break;
  517.         case 'u':
  518.             margin(+2);
  519.             *out << ++count << '.';
  520.             margin(+3);
  521.             break;
  522.         }
  523.     } else if (type == 'p')
  524.         *out << "<DT>"; /* *out << ":pt."; */
  525.     else
  526.         *out << "<LI>";
  527.  
  528.     if (text && *text) {
  529.         /* if (beg.fontname)
  530.             *out << ":font facename=" << beg.fontname
  531.                  << " size=" FontSize "."; */
  532.                 /*
  533.         if (beg.hpnumber == 100)
  534.             *out << "&sqbul.";
  535.         else if (beg.hpnumber)
  536.             *out << ":hp" << beg.hpnumber << '.';
  537.                         */
  538.         /* if (beg.delimiter)
  539.             *out << beg.delimiter; */
  540.  
  541.         //*out << text << endl; /* here I have added a endl to
  542.                 //                       * let the lines be more
  543.                 //                      * readable
  544.                 //                       */
  545.                 *out << text << endl << "<BR>" << endl;
  546.         /* if (end.delimiter)
  547.             *out << end.delimiter; */
  548.         /*if (end.hpnumber)
  549.             *out << ":ehp" << end.hpnumber << '.';*/
  550.         /* if (end.fontname)
  551.             *out << ":font facename=" << end.fontname
  552.                  << " size=" FontSize "."; */
  553.     }
  554.  
  555.     if (type == 'p') {
  556.         if (nested)
  557.             *out << "<DD>"; /* margin(+12);*/
  558.         else
  559.             *out << "<DD>"; /* *out << ":pd.";*/
  560.     }
  561. }
  562.  
  563. void
  564. item_end(const char *text)
  565. {
  566.     PUTL();
  567.     if (istackp->nested)
  568.         {
  569.                 PUT ("</DL>");
  570.         newpara = 1;
  571.         }
  572.     else {
  573.         PUT(text);
  574.         newpara = 0;
  575.     }
  576.     --istackp;
  577.     set_margin(istackp->indent);
  578. }
  579.  
  580. ////////////////////////////////////////////////////////////////////////
  581.  
  582. static void
  583. xentry(String& xk, XEntry& xe, const char *classname)
  584. {
  585.         int id = 0;
  586.  
  587.         if (debug)
  588.             cerr << "xentry:" << endl
  589.                  << "    xk=" << xk << endl
  590.                  << "    classname=" << classname << endl;
  591.  
  592.         *out << "<LI>" << xk << endl;
  593.     /*PUT(":pt." << xk << endl << ":pd.");*/
  594.     int ne = 0;
  595.         *out << "<UL>" << endl;
  596.         if (debug)
  597.             cerr << "xentry1:" << endl;
  598.     for (Pix item = xe.first(); item; xe.next(item))
  599.         {
  600.         /*if (ne++)
  601.             PUT(".br" << endl);*/
  602.         XItem& xi = xe(item);
  603.  
  604.         if (debug)
  605.                     cerr << "    title=" << xi.title << endl;
  606.                 /* don't allow to print doubled entries */
  607.                 if (id != xi.id)
  608.                 {
  609.                 *out << "<LI>"
  610.                      /* << "<A HREF=\"#" << classname << "_" << xi.title << "\">"*/
  611.                      /* << "<A HREF=\"#" << classname << "hd_" << xi.id << "\">" */
  612.                      << "<A HREF=\"#" << "hd_" << xi.id << "\">"
  613.                      << xi.title << "</A>" << endl;
  614.                 id = xi.id;
  615.                 }
  616.  
  617.         /*PUT(":link reftype=hd refid=hd" << xi.id << '.'
  618.          << xi.title << ":elink." << endl);*/
  619.     }
  620.         *out << "</UL>" << endl;
  621. }
  622.  
  623. void
  624. indexref(const char *classname, const String& text)
  625. {
  626.         if (debug)
  627.             cerr << "indexref:" << endl
  628.                  << "     classname=" << classname << endl
  629.                  << "     text=" << text << endl
  630.                  << "     panel_name=" << panel_name << endl;
  631.  
  632.         /* panel_name is the Text of the last heading (@chapter, @section...)
  633.          */
  634.     indexes[classname].entries[text].add(XItem(panel_name, panel_id));
  635.         *out << "<A NAME=\"" << classname << "_" << text << "\"></A>" << endl;
  636.         /* XItem
  637.         Pix item = indexes[classname].entries[text].contains();
  638.         */
  639.         /* *out << "<<INDEXREF CLASSNAME=\"" << classname << "\" TEXT=\"" << text << "\">>" << endl; */
  640.     if (f_index) {
  641.         static int id = 0;
  642.                 *out << "<<INDEXREF>>" << endl;
  643.         PUT(":i1 id=i" << ++id << '.' << text);
  644.         PUTL();
  645.     }
  646. }
  647.  
  648. void
  649. printindex(String& classname)
  650. {
  651.     XClassT& xc = indexes[classname].entries;
  652.     int ckeys[UCHAR_MAX+1], digit = 0, other = 0;
  653.     enum { Small, CType, Medium, Huge } mode;
  654.  
  655.     const Limit = 1000;
  656.  
  657.     if (xc.length() >= Limit) {
  658.         memset(ckeys, 0, sizeof ckeys);
  659.         for (Pix entry = xc.first(); entry; xc.next(entry)) {
  660.             unsigned char c = xc.key(entry)[0];
  661.             if (isalpha(c))
  662.                 ++ckeys[toupper(c)];
  663.             else
  664.                 ++ckeys[c];
  665.         }
  666.         mode = Medium;
  667.         for (int i = 0; i <= UCHAR_MAX; ++i) {
  668.             if (ckeys[i] >= Limit) {
  669.                 mode = Huge;
  670.                 break;
  671.             }
  672.             if (isdigit(i))
  673.                 digit += ckeys[i];
  674.             else if (!isalpha(i))
  675.                 other += ckeys[i];
  676.         }
  677.         if (mode == Medium && digit < Limit && other < Limit)
  678.             mode = CType;
  679.     } else
  680.         mode = Small;
  681.  
  682.     switch (mode) {
  683.  
  684.     case Huge: {
  685.  
  686.         int count = xc.length();
  687.         int chunk = count / 50;
  688.         int i = 0;
  689.         String *keys = new String [count];
  690.         Pix entry;
  691.                 *out << "<<HUGE>>" << endl;
  692.         for (entry = xc.first(); entry; xc.next(entry))
  693.             keys[i++] = xc.key(entry).before(' ');
  694.         i = 0;
  695.         for (entry = xc.first(); entry; xc.next(entry)) {
  696.             if (i % chunk == 0) {
  697.                 if (i)
  698.                     PUT(":eparml." << endl)
  699.                 PUT(":h" << hlevel+1 << '.'
  700.                      << keys[i]
  701.                      << "  &dot.&dot.&dot.  "
  702.                      << keys[min(i+chunk-1, count-1)]
  703.                      << endl);
  704.                 PUT(":parml tsize=50 break=none compact." << endl);
  705.             }
  706.             xentry(xc.key(entry), xc.contents(entry), classname);
  707.             ++i;
  708.         }
  709.         delete [] keys;
  710.         }
  711.         break;
  712.  
  713.     case Medium: {
  714.         unsigned char c0 = 0;
  715.                 *out << "<<MEDIUM>>" << endl;
  716.         for (Pix entry = xc.first(); entry; xc.next(entry)) {
  717.             unsigned char c = toupper(xc.key(entry)[0]);
  718.             if (c != c0) {
  719.                 if (c0)
  720.                     PUT(":eparml.");
  721.                 c0 = c;
  722.                 PUT(":h" << hlevel+1 << '.' << c << endl);
  723.                 PUT(":parml tsize=50 break=none compact." << endl);
  724.             }
  725.             xentry(xc.key(entry), xc.contents(entry), classname);
  726.         }
  727.         }
  728.         break;
  729.  
  730.     case CType: {
  731.         unsigned char c1, c2 = 0;
  732.                 *out << "<<CTYPE>>" << endl;
  733.         for (Pix entry = xc.first(); entry; xc.next(entry)) {
  734.             unsigned char c = toupper(xc.key(entry)[0]);
  735.             if (!isalpha(c))
  736.                 continue;
  737.             if (c > c2) {
  738.                 if (c2)
  739.                     PUT(":eparml." << endl);
  740.                 c1 = c;
  741.                 int n = ckeys[c1];
  742.                 for (c2 = c1; isalpha(c2+1); ++c2) {
  743.                     n += ckeys[c2+1];
  744.                     if (n > 100)
  745.                         break;
  746.                 }
  747.                 PUT(":h" << hlevel+1 << '.');
  748.                 if (c1 != c2)
  749.                     PUT(c1 << "&dot.&dot.&dot." << c2)
  750.                 else
  751.                     PUT(c1);
  752.                 PUT(endl);
  753.                 PUT(":parml tsize=50 break=none compact." << endl);
  754.             }
  755.             xentry(xc.key(entry), xc.contents(entry), classname);
  756.         }
  757.                 *out << "<<CTYPE1>>" << endl;
  758.         if (digit) {
  759.             PUT(":eparml." << endl);
  760.             PUT(":h" << hlevel+1 << ".0&dot.&dot.&dot.9" << endl);
  761.             PUT(":parml tsize=50 break=none compact." << endl);
  762.             for (Pix entry = xc.first(); entry; xc.next(entry)) {
  763.                 unsigned char c = toupper(xc.key(entry)[0]);
  764.                 if (isdigit(c))
  765.                     xentry(xc.key(entry), xc.contents(entry), classname);
  766.             }
  767.         }
  768.                 *out << "<<CTYPE2>>" << endl;
  769.         if (other) {
  770.             PUT(":eparml." << endl);
  771.             PUT(":h" << hlevel+1 << ".&dot.&dot.&dot." << endl);
  772.             PUT(":parml tsize=50 break=none compact." << endl);
  773.             for (Pix entry = xc.first(); entry; xc.next(entry)) {
  774.                 unsigned char c = toupper(xc.key(entry)[0]);
  775.                 if (!isalpha(c) && !isdigit(c))
  776.                     xentry(xc.key(entry), xc.contents(entry), classname);
  777.             }
  778.         }
  779.         }
  780.         break;
  781.  
  782.     case Small:
  783.                 /* *out << "<<SMALL>>" << endl;*/
  784.                 *out << "<UL>" << endl;
  785.         /*PUT(":parml tsize=50 break=none compact." << endl);*/
  786.         for (Pix entry = xc.first(); entry; xc.next(entry))
  787.             xentry(xc.key(entry), xc.contents(entry), classname);
  788.                 *out << "</UL>" << endl;
  789.     }
  790.     /*PUT(":eparml.");*/
  791.     /*PUTL();*/
  792. }
  793.  
  794. ////////////////////////////////////////////////////////////////////////
  795.  
  796. void
  797. single_word(const char *text)
  798. {
  799.     int ipf = 0;
  800.     while (*text) {
  801.         char c = *text++;
  802.         switch (c) {
  803.         case ' ':
  804.             if (ipf)
  805.                 break;
  806.             PUTS("&rbl.");
  807.             continue;
  808.         case ':':
  809.         case '&':
  810.             ipf = 1;
  811.             break;
  812.         }
  813.         PUTS(c);
  814.     }
  815. }
  816.  
  817. ////////////////////////////////////////////////////////////////////////
  818.  
  819. void
  820. para()
  821. {
  822.     if (!plevel) {
  823.                 *out << "<P>";
  824.         newpara = 0;
  825.     }
  826. }
  827.  
  828. ////////////////////////////////////////////////////////////////////////
  829.  
  830. void
  831. setflag(String& line)
  832. {
  833.         /*cerr << "setflag: " << line << endl;*/
  834.     int x = line.index(' ');
  835.         /*cerr << "setflag: " << x << endl;*/
  836.     if (x < 0)
  837.         {
  838.             x = line.index('=');
  839.         }
  840.  
  841.     if (x >= 0)
  842.         {
  843.         flags[line.before(x)] = line.after(x);
  844.                 /* cerr << "setflag: before=" << line.before(x) << " after=" << line.after(x) << endl;*/
  845.         }
  846.     else
  847.         flags[line] = "";
  848. }
  849.  
  850.  
  851.