home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / word2x0a.zip / source / html-embed.cc < prev    next >
C/C++ Source or Header  |  1997-04-22  |  7KB  |  372 lines

  1. /* $Id: html-embed.cc,v 1.8 1997/03/25 23:23:04 dps Exp $ */
  2. /* Embed handling for *TeX output */
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include "interface.h"
  7. #include "tblock.h"
  8. #include "fmt-html.h"
  9.  
  10.  
  11. /* Skip a term */
  12. const char *html_skip_to_next(const char *ptr)
  13. {
  14.     int blevel;
  15.     int ign_nxt;
  16.  
  17.     ign_nxt=0;
  18.     blevel=0;
  19.     while(1)
  20.     {
  21.     switch(*ptr)
  22.     {
  23.     case '\\':
  24.         ign_nxt=1;
  25.         break;
  26.  
  27.     case '(':
  28.         if (!ign_nxt)
  29.         blevel++;
  30.         break;
  31.  
  32.     case ')':
  33.         if (!ign_nxt)
  34.         blevel--;
  35.         if (blevel<0)
  36.         return ptr;
  37.         break;
  38.  
  39.     case ',':
  40.         if (!ign_nxt && blevel==0)
  41.         return ptr;
  42.         break;
  43.  
  44.     case '\0':
  45.         return ptr;
  46.  
  47.     default:
  48.         break;
  49.     }
  50.     ptr++;
  51.     }
  52. }
  53.  
  54.  
  55.  
  56. /* For detial of this see The TeXbook p. 141) */
  57. typedef enum {Disp=0, DispP, Text, TextP,
  58.           Script, ScriptP,
  59.           SScript, SScriptP } style;
  60.  
  61. enum TypeIndex { Op_Sup=0, Op_Sub, Op_FTop, Op_FBot };
  62. /* Style navigation map */
  63. static const style style_map[][4]=
  64. {
  65.     { Script, ScriptP, Text, TextP },        // style D
  66.     { ScriptP, ScriptP, TextP, TextP },        // style D'
  67.     { Script, ScriptP, Script, ScriptP },    // Style T
  68.     { ScriptP, ScriptP, ScriptP, ScriptP },    // Style T'
  69.     { SScript, SScriptP, SScript, SScriptP },    // Style S
  70.     { SScriptP, SScriptP, SScriptP, SScriptP },    // Style S'
  71.     { SScript, SScriptP, SScript, SScriptP },    // Style SS
  72.     { SScriptP, SScriptP, SScriptP, SScriptP }    // Style SS'
  73. };
  74.  
  75. /* The actual work is in this recursive procedure */
  76. static tblock *cvt_eqn(const char *inp, const char *stop,
  77.                const int mline, const style sty)
  78. {
  79.     tblock *res, *r1, *r2;
  80.     const char *mid, *end;
  81.  
  82.     
  83.     res=new(tblock);
  84.     while (inp<stop)
  85.     {
  86.     if (isspace(*inp) && *inp!='\n')
  87.     {
  88.         inp++;
  89.         continue;
  90.     }
  91.  
  92.     switch (*inp)
  93.     {
  94.     case '\0':
  95.         return res;
  96.     
  97.     case '\n':
  98.         if (mline)
  99.         res->add(" \\\\\n");
  100.         break;
  101.  
  102.     case '<':
  103.     case '>':
  104.     case '=':
  105.         if (mline)
  106.         {
  107.         res->add(" & ");
  108.         res->add(*inp);
  109.         res->add(" & ");
  110.         }
  111.         else
  112.         res->add(*inp);
  113.         break;
  114.  
  115.     case '\\':
  116.         inp++;
  117.         switch(*inp)
  118.         {
  119.         case '\0':
  120.         cerr<<"Bug: cvt_eqn as \\0\n";
  121.         return res;    // Safety.
  122.  
  123.         case '(':        // Guesswork FIXME
  124.         res->add(" (");
  125.         break;
  126.  
  127.         case ')':        // Guesswork FIXME
  128.         res->add(" )");
  129.         break;
  130.  
  131.         case 'F':        // Fraction
  132.         if (*(++inp)=='(' &&
  133.             *(mid=html_skip_to_next(++inp))!='\0' &&
  134.             *(end=html_skip_to_next(mid+1))!='\0')
  135.         {
  136.             r1=cvt_eqn(inp, mid, mline, style_map[sty][Op_FTop]);
  137.             r2=cvt_eqn(mid+1, end, mline, style_map[sty][Op_FBot]);
  138.             res->add(' '); 
  139.             res->add(*r1);
  140.             res->add(" / "); // TeX syntax
  141.             res->add(*r2); 
  142.             res->add(' ');
  143.             delete(r1); delete(r2);
  144.         }
  145.         inp=end;
  146.         break;
  147.         default:
  148.         end=html_skip_to_next(inp+1);
  149.         r1=cvt_eqn(inp+1, end, mline, sty);
  150.         res->add("<TT> \\backslash "); res->add(*inp);
  151.         res->add("</TT> "); res->add(*r1); res->add("<TT> ");
  152.         delete(r1);
  153.         inp=end;
  154.         break;
  155.         }
  156.         break;
  157.     case '+':
  158.     case '-':
  159.         res->add(*inp);
  160.         break;
  161.     case '*':
  162.         res->add(" * ");
  163.         break;
  164.  
  165.     case ' ':
  166.         res->add(" ");
  167.         break;
  168.  
  169.     case '_':
  170.         res->add("_");
  171.         break;
  172.  
  173.     default:
  174.         int flg=0;
  175.         const char *scn;
  176.  
  177.         /*
  178.          * This section is meant to catch 72 dpi and render it as
  179.          * \hbox{72 dpi} but not catch 12 * 18 (which should become
  180.          * 12\times 18).
  181.          */
  182.         if (isdigit(*inp) || *inp=='-' || *inp=='+')
  183.         {
  184.  
  185.         /* Scan forward to see what comes text */
  186.         scn=inp;        
  187.         if (*scn=='-' || *scn=='+')
  188.             scn++;    // Skip sign    
  189.         while (scn<stop && isdigit(*scn))
  190.             scn++;    // Skip number
  191.         if (*scn=='.')
  192.         {
  193.             scn++;
  194.             while (scn<stop && isdigit(*scn))
  195.             scn++;    //  Hanlde decimals number
  196.         }
  197.  
  198.         /* Now start looking at what comes next */
  199.         while (scn<stop)
  200.         {
  201.             if (isspace(*scn))
  202.             {
  203.             scn++;
  204.             continue;
  205.             }
  206.             if (isupper(*scn) || islower(*scn))
  207.             flg=1;
  208.             else
  209.             flg=0;
  210.             break;
  211.         }
  212.         }
  213.  
  214.         /*
  215.          * This section is meant to catch strings and render them nicely
  216.          * in a mbox.
  217.          */
  218.         if (islower(*inp) || isupper(*inp) || flg)
  219.         {
  220.         res->add("\\text{");         
  221.         if (flg)    // If flag set then add everything up to scn
  222.         {
  223.             while (inp<scn)
  224.             {
  225.             res->add(*inp);
  226.             inp++;
  227.             }
  228.         }
  229.  
  230.         flg=0;        // Re-use flg
  231.         while (inp<stop && (islower(*inp) || isupper(*inp)
  232.                     || isspace(*inp)
  233.                     || *inp=='_'
  234.                     || *inp=='^'))
  235.         {
  236.             if (isspace(*inp))
  237.             {
  238.             flg=1;
  239.             inp++;
  240.             continue;      // If space, just set the flag
  241.             }
  242.             if (flg)
  243.             res->add(' ');      // If skiped a space, add one
  244.             flg=0;          // Clear flag
  245.             if (*inp=='_' || *inp=='^')
  246.             res->add('\\');
  247.             res->add(*inp);
  248.             inp++;
  249.         }
  250.         res->add("} ");
  251.         inp--;
  252.         break;
  253.         }
  254.         res->add(*inp);
  255.         break;
  256.     }
  257.     inp++;
  258.     }
  259.     return res;
  260. }
  261.  
  262. /* Equations --- need more examples here */
  263. static void equation(const char *txt, const docfmt *fmt, FILE *out,
  264.              void *d)
  265. {
  266.  
  267.     static const cmap comment_map[]={ { '\n', "\n% (contd) % " } };
  268.     struct html_data *dp;
  269.     tblock *cvt, eqn, *op;
  270.     const char *s;
  271.     int mline;
  272.     
  273.     dp=(struct html_data *) d;
  274.     cvt=map_string(txt, comment_map);
  275.     fprintf(out, "%%\n%% EMBED %s\n", (const char *) (*cvt));
  276.     delete(cvt);
  277.  
  278.     for (mline=0, s=txt; *s!='\0'; s++)
  279.     {
  280.     if (*s=='\n')
  281.     {
  282.         mline=1;
  283.         break;
  284.     }
  285.     }
  286.     if (!mline)
  287.     eqn.add((dp->par_flg) ? "$" : "$$");
  288.     else
  289.     eqn.add("\\begin{eqnarray*}\n");
  290.     cvt=cvt_eqn(txt+3, txt+strlen(txt), mline, (dp->par_flg) ? Disp : Text);
  291.     eqn.add(*cvt);
  292.     delete(cvt);
  293.  
  294.     if (!mline)
  295.     eqn.add((dp->par_flg) ? "$" : "$$%");
  296.     else
  297.     eqn.add("\n\\end{eqnarray*}\n");
  298.  
  299.     op=word_wrap(eqn, "\n", "\n", fmt->maxline);
  300.     fputs((const char *) (*op), out);
  301.     fputc('\n', out);
  302.     delete(op);
  303. }
  304.     
  305.  
  306.  
  307. /* Table of contents entries, used as a cue for stuff like sections */
  308. /* This code jus stashes it away for the paragraph code */
  309. static void add_contents(const char *txt, const docfmt *fmt, FILE *out,
  310.              void *d)
  311. {
  312.     const char *open, *close;
  313.     tblock entry;
  314.     struct html_data *dp;
  315.  
  316.     fmt=fmt;
  317.     out=out;
  318.     dp=(struct html_data *) d;
  319.     for (open=txt; *open!='"'; open++)
  320.     {
  321.     if (*open=='\0')
  322.     {
  323.         cerr<<"Found tc entry but no openning quote\n";
  324.         return;
  325.     }
  326.     }
  327.     
  328.     for (close=open+1; *close!='"'; close++)
  329.     {
  330.     if (*close=='\0')
  331.     {
  332.         cerr<<"Found tc entry but no closing quote\n";
  333.         return;
  334.     }
  335.     }
  336.  
  337.     if (close-open==1)
  338.     {
  339.     cerr<<"Ignoring empty table of contents entry\n";
  340.     return;
  341.     }
  342.  
  343.     while (++open<close)
  344.     entry.add(*open);
  345.     if (dp->last_tc!=NULL)
  346.     free((void *) dp->last_tc);
  347.     dp->last_tc=strdup(entry);
  348.  
  349. }
  350.  
  351. static struct embed emb[]=
  352. {
  353.     { "tc ", 3, add_contents },    // Table of contents line
  354.     { "eq ", 3, equation },    // Equations
  355. };
  356.  
  357. void html_embed(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
  358.            void *d)
  359.     int i;
  360.  
  361.     for (i=0; (unsigned) i<N(emb); i++)
  362.     {
  363.     if (strncmp(t->data.d, emb[i].key, emb[i].key_len)==0)
  364.     {
  365.         (emb[i].handle)(t->data.d, fmt, out, d);
  366.         return;
  367.     }
  368.     }
  369.     fprintf(out, "%%\n%% %s\n", t->data.d);
  370. }
  371.