/* $Id: html-embed.cc,v 1.8 1997/03/25 23:23:04 dps Exp $ */ /* Embed handling for *TeX output */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #ifdef HAVE_STRING_H #include #endif /* HAVE_STRING_H */ #ifdef HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #ifdef HAVE_CTYPE_H #include #endif /* HAVE_CTYPE_H */ #include "interface.h" #include "tblock.h" #include "fmt-html.h" /* Skip a term */ const char *html_skip_to_next(const char *ptr) { int blevel; int ign_nxt; ign_nxt=0; blevel=0; while(1) { switch(*ptr) { case '\\': ign_nxt=1; break; case '(': if (!ign_nxt) blevel++; break; case ')': if (!ign_nxt) blevel--; if (blevel<0) return ptr; break; case ',': if (!ign_nxt && blevel==0) return ptr; break; case '\0': return ptr; default: break; } ptr++; } } /* For detial of this see The TeXbook p. 141) */ typedef enum {Disp=0, DispP, Text, TextP, Script, ScriptP, SScript, SScriptP } style; enum TypeIndex { Op_Sup=0, Op_Sub, Op_FTop, Op_FBot }; /* Style navigation map */ static const style style_map[][4]= { { Script, ScriptP, Text, TextP }, // style D { ScriptP, ScriptP, TextP, TextP }, // style D' { Script, ScriptP, Script, ScriptP }, // Style T { ScriptP, ScriptP, ScriptP, ScriptP }, // Style T' { SScript, SScriptP, SScript, SScriptP }, // Style S { SScriptP, SScriptP, SScriptP, SScriptP }, // Style S' { SScript, SScriptP, SScript, SScriptP }, // Style SS { SScriptP, SScriptP, SScriptP, SScriptP } // Style SS' }; /* The actual work is in this recursive procedure */ static tblock *cvt_eqn(const char *inp, const char *stop, const int mline, const style sty) { tblock *res, *r1, *r2; const char *mid, *end; res=new(tblock); while (inpadd(" \\\\\n"); break; case '<': case '>': case '=': if (mline) { res->add(" & "); res->add(*inp); res->add(" & "); } else res->add(*inp); break; case '\\': inp++; switch(*inp) { case '\0': cerr<<"Bug: cvt_eqn as \\0\n"; return res; // Safety. case '(': // Guesswork FIXME res->add(" ("); break; case ')': // Guesswork FIXME res->add(" )"); break; case 'F': // Fraction if (*(++inp)=='(' && *(mid=html_skip_to_next(++inp))!='\0' && *(end=html_skip_to_next(mid+1))!='\0') { r1=cvt_eqn(inp, mid, mline, style_map[sty][Op_FTop]); r2=cvt_eqn(mid+1, end, mline, style_map[sty][Op_FBot]); res->add(' '); res->add(*r1); res->add(" / "); // TeX syntax res->add(*r2); res->add(' '); delete(r1); delete(r2); } inp=end; break; default: end=html_skip_to_next(inp+1); r1=cvt_eqn(inp+1, end, mline, sty); res->add(" \\backslash "); res->add(*inp); res->add(" "); res->add(*r1); res->add(" "); delete(r1); inp=end; break; } break; case '+': case '-': res->add(*inp); break; case '*': res->add(" * "); break; case ' ': res->add(" "); break; case '_': res->add("_"); break; default: int flg=0; const char *scn; /* * This section is meant to catch 72 dpi and render it as * \hbox{72 dpi} but not catch 12 * 18 (which should become * 12\times 18). */ if (isdigit(*inp) || *inp=='-' || *inp=='+') { /* Scan forward to see what comes text */ scn=inp; if (*scn=='-' || *scn=='+') scn++; // Skip sign while (scnadd("\\text{"); if (flg) // If flag set then add everything up to scn { while (inpadd(*inp); inp++; } } flg=0; // Re-use flg while (inpadd(' '); // If skiped a space, add one flg=0; // Clear flag if (*inp=='_' || *inp=='^') res->add('\\'); res->add(*inp); inp++; } res->add("} "); inp--; break; } res->add(*inp); break; } inp++; } return res; } /* Equations --- need more examples here */ static void equation(const char *txt, const docfmt *fmt, FILE *out, void *d) { static const cmap comment_map[]={ { '\n', "\n% (contd) % " } }; struct html_data *dp; tblock *cvt, eqn, *op; const char *s; int mline; dp=(struct html_data *) d; cvt=map_string(txt, comment_map); fprintf(out, "%%\n%% EMBED %s\n", (const char *) (*cvt)); delete(cvt); for (mline=0, s=txt; *s!='\0'; s++) { if (*s=='\n') { mline=1; break; } } if (!mline) eqn.add((dp->par_flg) ? "$" : "$$"); else eqn.add("\\begin{eqnarray*}\n"); cvt=cvt_eqn(txt+3, txt+strlen(txt), mline, (dp->par_flg) ? Disp : Text); eqn.add(*cvt); delete(cvt); if (!mline) eqn.add((dp->par_flg) ? "$" : "$$%"); else eqn.add("\n\\end{eqnarray*}\n"); op=word_wrap(eqn, "\n", "\n", fmt->maxline); fputs((const char *) (*op), out); fputc('\n', out); delete(op); } /* Table of contents entries, used as a cue for stuff like sections */ /* This code jus stashes it away for the paragraph code */ static void add_contents(const char *txt, const docfmt *fmt, FILE *out, void *d) { const char *open, *close; tblock entry; struct html_data *dp; fmt=fmt; out=out; dp=(struct html_data *) d; for (open=txt; *open!='"'; open++) { if (*open=='\0') { cerr<<"Found tc entry but no openning quote\n"; return; } } for (close=open+1; *close!='"'; close++) { if (*close=='\0') { cerr<<"Found tc entry but no closing quote\n"; return; } } if (close-open==1) { cerr<<"Ignoring empty table of contents entry\n"; return; } while (++openlast_tc!=NULL) free((void *) dp->last_tc); dp->last_tc=strdup(entry); } static struct embed emb[]= { { "tc ", 3, add_contents }, // Table of contents line { "eq ", 3, equation }, // Equations }; void html_embed(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { int i; for (i=0; (unsigned) idata.d, emb[i].key, emb[i].key_len)==0) { (emb[i].handle)(t->data.d, fmt, out, d); return; } } fprintf(out, "%%\n%% %s\n", t->data.d); }