home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / txict100.zip / texicvt1.00 / source / utilrtf.cc < prev    next >
C/C++ Source or Header  |  1997-03-31  |  21KB  |  814 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 the converter Texinfo to RTF
  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: UTILRTF.CC 1.3 1997/03/22 17:36:44 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.         PUTL ();
  100.         PUT ("\\par {\\f11 ");
  101.     /*margin(+10);*/
  102.     fstack[++fstackx] = fontname;
  103.     /*font(0);*/
  104.     PUTL();
  105.     newpara = 0;
  106. }
  107.  
  108. void
  109. end_example()
  110. {
  111.     newpara = 0;
  112.     --nofill;
  113.     --fstackx;
  114.     /*font(0);*/
  115.     /*margin(-10);*/
  116.         PUT ("\\par }"); PUTL ();
  117.     /**out << "</PRE>" << endl;*/
  118.     /*PUTL();*/
  119.     newpara = 0;
  120. }
  121.  
  122. ////////////////////////////////////////////////////////////////////////
  123.  
  124. void
  125. words(String& line)
  126. {
  127.     int i = 0;
  128.     String tmp;
  129.     int pos;
  130.     for (const char *p1 = line.chars(), *end = p1 + line.length();;) {
  131.         while (p1 < end && isspace(*p1))
  132.             ++p1;
  133.         if (p1 == end)
  134.             break;
  135.         const char *p2 = p1;
  136.         while (p2 < end && *p2 != ',')
  137.             ++p2;
  138.         if (i < MaxW)
  139.         {
  140.             tmp = String (p1, p2 - p1);
  141.             if (tmp.length ())
  142.             {
  143.             pos = tmp.length ()-1;
  144.             
  145.                 while (tmp.length () && (isspace(tmp[pos]) || tmp[pos] == '\t'))
  146.                 tmp.del (pos--,1);
  147.             }
  148.             w[i++] = tmp;
  149.         }
  150.         if (p2 == end)
  151.             break;
  152.         p1 = p2 + 1;
  153.     }
  154.     while (i < MaxW)
  155.         w[i++] = null;
  156. }
  157.  
  158. void
  159. spaced(String& line)
  160. {
  161.     int i = 0;
  162.     for (const char *p1 = line.chars(), *end = p1 + line.length();;) {
  163.         while (p1 < end && isspace(*p1))
  164.             ++p1;
  165.         if (p1 == end)
  166.             break;
  167.         const char *p2 = p1;
  168.         while (p2 < end && !isspace(*p2))
  169.             ++p2;
  170.         if (i < MaxW)
  171.             w[i++] = String(p1, p2 - p1);
  172.         if (p2 == end)
  173.             break;
  174.         p1 = p2 + 1;
  175.     }
  176.     while (i < MaxW)
  177.         w[i++] = null;
  178. }
  179.  
  180. ////////////////////////////////////////////////////////////////////////
  181.  
  182. static int    hstack[6];
  183. static int    hlevel = 0;
  184.  
  185. void
  186. heading(int level, const char *s)
  187. {
  188.     if (istackp != istack)
  189.         return;
  190.     if (f_node) {
  191.         if (preface)
  192.             PUT(":h2." << s << endl << ":lm margin=1.");
  193.     }
  194.         /*else { */
  195.         if (debug)
  196.             cerr << "Heading, logical level=" << level
  197.                  << " stack level=" << hlevel
  198.                  << " stacked=" << hstack[hlevel];
  199.         if (level > hstack[hlevel])
  200.             hstack[++hlevel] = level;
  201.         else while (level < hstack[hlevel])
  202.             --hlevel;
  203.         if (debug)
  204.             cerr << " panel level=" << hlevel << endl;
  205.         if (node_id) {
  206.             panel_id = node_id;
  207.             node_id = 0;
  208.         } else
  209.             panel_id = ++hdid;
  210.         panel_name = s;
  211.                 /* *out << "\\page {\\cs16\\super" << endl; */
  212.                 *out << "{\\cs16\\super" << endl;
  213.                 *out << "${\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super $}" << s << "}" << endl;
  214.                 *out << "}" << endl;
  215.                 *out << "\\pard \\qc\\brdrb\\brdrs\\brdrw15\\brsp20  {\\b\\fs28 " << s << endl;
  216.                 *out << "\\par }" << endl;
  217.                 *out << "\\pard \\par " << endl;
  218.  
  219.                 /*PUT("<H" << hlevel << ">" << s << "</H" << hlevel << ">" << endl);*/
  220.         /*PUT(":h" << hlevel << " id=hd" << panel_id << '.' << s
  221.              << endl << ":lm margin=1.");*/
  222.  /*    } */
  223. }
  224.  
  225.  
  226. void
  227. Menu::flush()
  228. {
  229.  
  230.     int x1;
  231.     int x2;
  232.     String name;
  233.     String Node;
  234.     String Filename;
  235.     String Text;
  236.  
  237.     if (!line.length())
  238.         return;
  239.  
  240.     x1 = line.index(":");
  241.     if (debug)
  242.         cerr << "Menu::flush ()" << endl
  243.              << "    line=\"" << line << "\"" << endl;
  244.  
  245.  
  246.     if (x1>=0)
  247.     {
  248.         x2 = line.index (":", x1+1);
  249.         /* Is this a menu entry like:
  250.            * Node::   discription
  251.          */
  252.         if (x2 > 0)
  253.         {
  254.             /* Yes it is. */
  255.             if ((x2-x1) == 1)
  256.                 name = line.before (x1);
  257.             else
  258.                 cerr << "Menu::flush ()" << endl
  259.                      << "    the second colon is not positioned after the first!" << endl;
  260.  
  261.             if (!table.contains(name))
  262.                 table[name] = Name(++hdid);
  263.  
  264.             for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
  265.                 ;
  266.  
  267.             Node = line.before (x1);
  268.             Text = line.from (x2);
  269.             if (!Text.length ())
  270.                 Text = Node;
  271.  
  272.             *out << "\\par {\\strike " << Text << "}" <<
  273.                     "{\\v " << Node << "}" << endl;
  274.  
  275.         }
  276.         else
  277.         {
  278.             /* If we came here it might be an
  279.              * entry like this:
  280.                  * Entry: node-name.   Discription
  281.              */
  282.             /* search the positition of the dot */
  283.             x2 = line.index (".", x1+1);
  284.  
  285.             for (x1 += 1; x1 < line.length() && isspace(line[x1]); ++x1)
  286.                 ;
  287.             name = line.at (x1, x2-x1);
  288.  
  289.             for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
  290.                 ;
  291.  
  292.             /* check if a file name is part of the node */
  293.             if (name.index("(", 1) == 1)
  294.             {
  295.                 /* extract the file name */
  296.                 Filename = name.at (name.index("(",1), name.index (")", 2));
  297.                 while (name[0]!=')' && name.length ())
  298.                     name.del(0,1);
  299.             }
  300.             else
  301.                 Filename = "";
  302.  
  303.             if (Filename.length())
  304.             {
  305.                 /* Node out of another file */
  306.                 cerr << "Menu::line ()" << endl
  307.                      << "  actualy we don't support this" << endl;
  308.             }
  309.             else
  310.             {
  311.             }
  312.  
  313.                 Text =  line.from (x2);
  314.                 if (!Text.length ())
  315.                     Text = name;
  316.  
  317.                 if (!table.contains(name))
  318.                     table[name] = Name(++hdid);
  319.                 *out << "\\par {\\strike " << Text << "}" <<
  320.                         "{\\v " << name << "}" << endl;
  321.  
  322.             if (debug)
  323.                 cerr << "*** Node=\"" << name << "\"" << endl
  324.                      << "    Text=\"" << Text << "\"" << endl
  325.                      << "    File=\"" << Filename << "\"" << endl;
  326.         }
  327.     } /* if (x1>=0)... */
  328.  
  329. /****************************
  330.         if (debug)
  331.             cerr << "Menu::flush (): line=\"" << line << "\"" << endl;
  332.  
  333.     if (line.length() == 0)
  334.         return;
  335.     int x1 = line.index(":");
  336.     if (x1 >= 0) {
  337.         int x2 = line.index(":", x1+1);
  338.         if (x2 >= 0) {
  339.             String name = line.at(x1+1, x2-x1-1);
  340.             if (name.length() == 0)
  341.                 name = line.before(x1);
  342.             if (!table.contains(name))
  343.                 table[name] = Name(++hdid);
  344.             for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
  345.                 ;
  346.  
  347.                         *out << "\\par {\\strike " << line.from(x2) << "}" <<
  348.                                 "{\\v " << line.before(x1) << "}" << endl;
  349.         }
  350.     }
  351. ******************************/
  352.     line = "";
  353. }
  354.  
  355. void
  356. node(String name, String next, String prev, String up)
  357. {
  358.     int NodeId;
  359.     char Buffer[20];
  360.  
  361.     if (table.contains(up)) {
  362.         if (f_node)
  363.             hlevel = table[up].level + 1;
  364.     } else if (name == "Top" || up.length() == 0) {
  365.         if (f_node)
  366.             hlevel = 0;
  367.     } else {
  368.         cerr << "<up> node undefined in '" << name << "', '" << next
  369.             << "', '" << prev << "', '" << up << '\'' << endl;
  370.         cerr.flush();
  371. #if 0
  372.         exit(1);
  373. #endif
  374.     }
  375.     if (debug)
  376.         cerr << "Define name='" << name << "' next='" << next
  377.              << "' prev='" << prev << "' up='" << up << "'";
  378.     Name& entry = table[name];
  379.     if (entry.id) {
  380.         if (entry.defined) {
  381.             cerr << "Node '" << name << "' redefined " << endl;
  382.             cerr.flush();
  383. #if 0
  384.             exit(1);
  385. #endif
  386.         }
  387.         entry.defined = 1;
  388.         if (debug)
  389.             cerr << ", known id=" << entry.id << endl;
  390.     } else {
  391.         table[name] = Name(++hdid, 1, hlevel);
  392.         if (debug)
  393.             cerr << ", new id=" << hdid << endl;
  394.     }
  395.     if (f_node && hlevel >= 1 && hlevel <= 6 && istackp == istack)
  396.         {
  397.         preface = 0;
  398.                 *out << "\\page {\\cs16\\super" << endl;
  399.                 *out << "#{\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super #}" << name << "}" << endl;
  400.                 /* create only if the next node exists */
  401.                 if (next.length ())
  402.                 {
  403.                     NodeId = entry.id;
  404.                     sprintf (Buffer, "%04d", NodeId);
  405.                     *out << "+{\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super +}" << Buffer << "}" << endl;
  406.                 }
  407.                 /* *out << "${\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super $}" << name << "}" << endl; */
  408.                 *out << "}" << endl;
  409. /* #{\footnote \pard\plain \s15 \f4\fs20\lang1031 {\cs16\super #}ThirdThema}
  410. K{\footnote \pard\plain \s15 \f4\fs20\lang1031 {\cs16\super K}entfernen;loeschen;usw}
  411. +{\footnote \pard\plain \s15 \f4\fs20\lang1031 {\cs16\super +}Contents}}
  412. \par Hier wird Loeschen Text definiert.
  413.  */
  414.  
  415.                 /*PUT("<A NAME=\"" << name << "\">" << endl);*/
  416.         /* PUT(":h" << hlevel << " id=hd" << entry.id << '.' << name
  417.              << endl << ":lm margin=1."); */
  418.     }
  419.     node_name = name;
  420.     node_id = entry.id;
  421. }
  422.  
  423. void
  424. xref(char *see, String name, String entry, String topic, String file, String manual)
  425. {
  426.     if (debug)
  427.         cerr << "Refer to name='" << name << "' entry='" << entry
  428.              << "' topic='" << topic << "' file='" << file
  429.              << "' manual='" << manual << "'";
  430.     if (see)
  431.         PUTS(see);
  432.     if (file.empty()) {
  433.         if (!table.contains(name)) {
  434.             table[name] = Name(++hdid);
  435.             if (debug)
  436.                 cerr << " new id=" << hdid << endl;
  437.         } else
  438.             if (debug)
  439.                 cerr << " known id=" << table[name].id << endl;
  440.  
  441.                 *out << "{\\strike " << name << "}"
  442.                      << "{\\v ";
  443.                 /* *out << "<A HREF=\"#" << name << "\">";*/
  444.         /*PUTS(":link reftype=hd refid=hd" << table[name].id << '.');*/
  445.         if (topic.length()) {
  446.             /*PUT(topic);*/ *out << topic;
  447.         } else
  448.             /*PUT(name);*/ *out << name;
  449.         if (entry.length())
  450.                     *out << "<H1>" << entry << "</H1>";
  451.             /*PUT(": " << entry);*/
  452.  
  453.         *out << name << "}";
  454.     } else
  455.                 *out << "Section " << topic << " of <H1>" << manual << "</H1>";
  456.         /*PUTS("Section " << topic << " of :hp1." << manual << ":ehp1.");*/
  457. }
  458.  
  459. ////////////////////////////////////////////////////////////////////////
  460.  
  461. static int current_margin = 0;
  462.  
  463. static void
  464. set_margin(int indent)
  465. {
  466.     current_margin = indent;
  467.     /*PUTA(":lm margin=" << (1 + current_margin) << '.');*/
  468. }
  469.  
  470.     // > 0: indent
  471.     // < 0: extend
  472.     // = 0: reset
  473. int
  474. margin(int delta)
  475. {
  476.     int old = current_margin;
  477.     if (delta) {
  478.         current_margin += delta;
  479.         if (current_margin < 0)
  480.             current_margin = 0;
  481.     } else
  482.         current_margin = 0;
  483.     /*PUTA(":lm margin=" << (1 + current_margin) << '.');*/
  484.     return old;
  485. }
  486.  
  487. void
  488. item_begin(const char *text, int it, char *ic)
  489. {
  490.     if (istackp == istack) {
  491.         istackp->indent = current_margin;
  492.         istackp->nested = 1;
  493.     }
  494.     ++istackp;
  495.     istackp->type = it;
  496.     istackp->cat = ic;
  497.     istackp->beg = Item();
  498.     istackp->end = Item();
  499.     istackp->indent = current_margin;
  500.     switch (it) {
  501.     case 'o':
  502.         istackp->indent += 3;
  503.         break;
  504.     case 'u':
  505.         istackp->indent += 5;
  506.         break;
  507.     case 'p':
  508.         istackp->indent += 12;
  509.         break;
  510.     }
  511.     istackp->nested = 0;
  512.     istackp->count = 0;
  513.     for (ItemType *p = istack; p < istackp; ++p)
  514.         if (p->type == 'p')
  515.             ++istackp->nested;
  516.     /*PUTL();*/
  517.     if (!istackp->nested)
  518.         PUT(text);
  519.     newpara = 0;
  520. }
  521.  
  522. void
  523. ItemType::item(const char *text)
  524. {
  525.     newpara = 0;
  526.  
  527.         if (debug)
  528.             cerr << "ItemType::item (): \"" << text << "\"" << endl;
  529.  
  530.     if (nested) {
  531.         set_margin((istackp-1)->indent);
  532.         *out << ":p.";
  533.         switch (type) {
  534.         case 'o':
  535.             margin(+1);
  536.             *out << ".&larrow.";
  537.             margin(+2);
  538.             break;
  539.         case 'u':
  540.             margin(+2);
  541.             *out << ++count << '.';
  542.             margin(+3);
  543.             break;
  544.         }
  545.     } else if (type == 'p')
  546.         *out << ":pt.";
  547.     else
  548.         *out << "\\par ";
  549.  
  550.     if (text && *text) {
  551.         if (beg.fontname)
  552.             *out << ":font facename=" << beg.fontname
  553.                  << " size=" FontSize ".";
  554.         if (beg.hpnumber == 100)
  555.             *out << "&sqbul.";
  556.         else if (beg.hpnumber)
  557.             *out << ":hp" << beg.hpnumber << '.';
  558.         if (beg.delimiter)
  559.             *out << beg.delimiter;
  560.  
  561.         *out << text << " ";
  562.  
  563.         if (end.delimiter)
  564.             *out << end.delimiter;
  565.         if (end.hpnumber)
  566.             *out << ":ehp" << end.hpnumber << '.';
  567.         if (end.fontname)
  568.             *out << ":font facename=" << end.fontname
  569.                  << " size=" FontSize ".";
  570.     }
  571.  
  572.     if (type == 'p') {
  573.         if (nested)
  574.             margin(+12);
  575.         else
  576.             *out << ":pd.";
  577.     }
  578. }
  579.  
  580. void
  581. item_end(const char *text)
  582. {
  583.     PUTL();
  584.     if (istackp->nested)
  585.         newpara = 1;
  586.     else {
  587.         PUT(text);
  588.         newpara = 0;
  589.     }
  590.     --istackp;
  591.     set_margin(istackp->indent);
  592. }
  593.  
  594. ////////////////////////////////////////////////////////////////////////
  595.  
  596. static void
  597. xentry(String& xk, XEntry& xe)
  598. {
  599.     PUT(":pt." << xk << endl << ":pd.");
  600.     int ne = 0;
  601.     for (Pix item = xe.first(); item; xe.next(item)) {
  602.         if (ne++)
  603.             PUT(".br" << endl);
  604.         XItem& xi = xe(item);
  605.         PUT(":link reftype=hd refid=hd" << xi.id << '.'
  606.          << xi.title << ":elink." << endl);
  607.     }
  608. }
  609.  
  610. void
  611. indexref(const char *classname, const String& text)
  612. {
  613.     indexes[classname].entries[text].add(XItem(panel_name, panel_id));
  614.     if (f_index) {
  615.         static int id = 0;
  616.         PUT(":i1 id=i" << ++id << '.' << text);
  617.         PUTL();
  618.     }
  619. }
  620.  
  621. void
  622. printindex(String& classname)
  623. {
  624.     XClassT& xc = indexes[classname].entries;
  625.     int ckeys[UCHAR_MAX+1], digit = 0, other = 0;
  626.     enum { Small, CType, Medium, Huge } mode;
  627.  
  628.     const Limit = 1000;
  629.  
  630.     if (xc.length() >= Limit) {
  631.         memset(ckeys, 0, sizeof ckeys);
  632.         for (Pix entry = xc.first(); entry; xc.next(entry)) {
  633.             unsigned char c = xc.key(entry)[0];
  634.             if (isalpha(c))
  635.                 ++ckeys[toupper(c)];
  636.             else
  637.                 ++ckeys[c];
  638.         }
  639.         mode = Medium;
  640.         for (int i = 0; i <= UCHAR_MAX; ++i) {
  641.             if (ckeys[i] >= Limit) {
  642.                 mode = Huge;
  643.                 break;
  644.             }
  645.             if (isdigit(i))
  646.                 digit += ckeys[i];
  647.             else if (!isalpha(i))
  648.                 other += ckeys[i];
  649.         }
  650.         if (mode == Medium && digit < Limit && other < Limit)
  651.             mode = CType;
  652.     } else
  653.         mode = Small;
  654.  
  655.     switch (mode) {
  656.  
  657.     case Huge: {
  658.         int count = xc.length();
  659.         int chunk = count / 50;
  660.         int i = 0;
  661.         String *keys = new String [count];
  662.         Pix entry;
  663.         for (entry = xc.first(); entry; xc.next(entry))
  664.             keys[i++] = xc.key(entry).before(' ');
  665.         i = 0;
  666.         for (entry = xc.first(); entry; xc.next(entry)) {
  667.             if (i % chunk == 0) {
  668.                 if (i)
  669.                     PUT(":eparml." << endl)
  670.                 PUT(":h" << hlevel+1 << '.'
  671.                      << keys[i]
  672.                      << "  &dot.&dot.&dot.  "
  673.                      << keys[min(i+chunk-1, count-1)]
  674.                      << endl);
  675.                 PUT(":parml tsize=50 break=none compact." << endl);
  676.             }
  677.             xentry(xc.key(entry), xc.contents(entry));
  678.             ++i;
  679.         }
  680.         delete [] keys;
  681.         }
  682.         break;
  683.  
  684.     case Medium: {
  685.         unsigned char c0 = 0;
  686.         for (Pix entry = xc.first(); entry; xc.next(entry)) {
  687.             unsigned char c = toupper(xc.key(entry)[0]);
  688.             if (c != c0) {
  689.                 if (c0)
  690.                     PUT(":eparml.");
  691.                 c0 = c;
  692.                 PUT(":h" << hlevel+1 << '.' << c << endl);
  693.                 PUT(":parml tsize=50 break=none compact." << endl);
  694.             }
  695.             xentry(xc.key(entry), xc.contents(entry));
  696.         }
  697.         }
  698.         break;
  699.  
  700.     case CType: {
  701.         unsigned char c1, c2 = 0;
  702.         for (Pix entry = xc.first(); entry; xc.next(entry)) {
  703.             unsigned char c = toupper(xc.key(entry)[0]);
  704.             if (!isalpha(c))
  705.                 continue;
  706.             if (c > c2) {
  707.                 if (c2)
  708.                     PUT(":eparml." << endl);
  709.                 c1 = c;
  710.                 int n = ckeys[c1];
  711.                 for (c2 = c1; isalpha(c2+1); ++c2) {
  712.                     n += ckeys[c2+1];
  713.                     if (n > 100)
  714.                         break;
  715.                 }
  716.                 PUT(":h" << hlevel+1 << '.');
  717.                 if (c1 != c2)
  718.                     PUT(c1 << "&dot.&dot.&dot." << c2)
  719.                 else
  720.                     PUT(c1);
  721.                 PUT(endl);
  722.                 PUT(":parml tsize=50 break=none compact." << endl);
  723.             }
  724.             xentry(xc.key(entry), xc.contents(entry));
  725.         }
  726.         if (digit) {
  727.             PUT(":eparml." << endl);
  728.             PUT(":h" << hlevel+1 << ".0&dot.&dot.&dot.9" << endl);
  729.             PUT(":parml tsize=50 break=none compact." << endl);
  730.             for (Pix entry = xc.first(); entry; xc.next(entry)) {
  731.                 unsigned char c = toupper(xc.key(entry)[0]);
  732.                 if (isdigit(c))
  733.                     xentry(xc.key(entry), xc.contents(entry));
  734.             }
  735.         }
  736.         if (other) {
  737.             PUT(":eparml." << endl);
  738.             PUT(":h" << hlevel+1 << ".&dot.&dot.&dot." << endl);
  739.             PUT(":parml tsize=50 break=none compact." << endl);
  740.             for (Pix entry = xc.first(); entry; xc.next(entry)) {
  741.                 unsigned char c = toupper(xc.key(entry)[0]);
  742.                 if (!isalpha(c) && !isdigit(c))
  743.                     xentry(xc.key(entry), xc.contents(entry));
  744.             }
  745.         }
  746.         }
  747.         break;
  748.  
  749.     case Small:
  750.         PUT(":parml tsize=50 break=none compact." << endl);
  751.         for (Pix entry = xc.first(); entry; xc.next(entry))
  752.             xentry(xc.key(entry), xc.contents(entry));
  753.     }
  754.     PUT(":eparml.");
  755.     PUTL();
  756. }
  757.  
  758. ////////////////////////////////////////////////////////////////////////
  759.  
  760. void
  761. single_word(const char *text)
  762. {
  763.     int ipf = 0;
  764.     while (*text) {
  765.         char c = *text++;
  766.         switch (c) {
  767.         case ' ':
  768.             if (ipf)
  769.                 break;
  770.             PUTS("&rbl.");
  771.             continue;
  772.         case ':':
  773.         case '&':
  774.             ipf = 1;
  775.             break;
  776.         }
  777.         PUTS(c);
  778.     }
  779. }
  780.  
  781. ////////////////////////////////////////////////////////////////////////
  782.  
  783. void
  784. para()
  785. {
  786.     if (!plevel) {
  787.                 PUT ("\\par \\par "); /* *out << "<P>"; */
  788.         newpara = 0;
  789.     }
  790. }
  791.  
  792. ////////////////////////////////////////////////////////////////////////
  793.  
  794. void
  795. setflag(String& line)
  796. {
  797.         /*cerr << "setflag: " << line << endl;*/
  798.     int x = line.index(' ');
  799.         /*cerr << "setflag: " << x << endl;*/
  800.     if (x < 0)
  801.         {
  802.             x = line.index('=');
  803.         }
  804.  
  805.     if (x >= 0)
  806.         {
  807.         flags[line.before(x)] = line.after(x);
  808.                 /* cerr << "setflag: before=" << line.before(x) << " after=" << line.after(x) << endl;*/
  809.         }
  810.     else
  811.         flags[line] = "";
  812. }
  813.  
  814.