diff options
Diffstat (limited to 'support/word2x/latex-embed.cc')
-rw-r--r-- | support/word2x/latex-embed.cc | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/support/word2x/latex-embed.cc b/support/word2x/latex-embed.cc new file mode 100644 index 0000000000..810e3a17ad --- /dev/null +++ b/support/word2x/latex-embed.cc @@ -0,0 +1,555 @@ +/* $Id: latex-embed.cc,v 1.12 1997/04/17 20:03:19 dps Exp $ */ +/* Embed handling for *TeX output */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ +#include <stdio.h> +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif /* HAVE_CTYPE_H */ +#include "interface.h" +#include "tblock.h" +#include "fmt-latex.h" + + +/* 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, Op_Cramp }; +/* Style navigation map */ +static const style style_map[][5]= +{ + { Script, ScriptP, Text, TextP, DispP }, // style D + { ScriptP, ScriptP, TextP, TextP, DispP }, // style D' + { Script, ScriptP, Script, ScriptP, TextP }, // Style T + { ScriptP, ScriptP, ScriptP, ScriptP, TextP }, // Style T' + { SScript, SScriptP, SScript, SScriptP, ScriptP }, // Style S + { SScriptP, SScriptP, SScriptP, SScriptP, ScriptP }, // Style S' + { SScript, SScriptP, SScript, SScriptP, SScriptP }, // Style SS + { SScriptP, SScriptP, SScriptP, SScriptP, SScriptP } // Style SS' +}; + +static tblock *cvt_eqn(const char *, const char *, const int, const style); + + +/* Skip a term */ +const char *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++; + } +} + + +/* Equation sub-bits */ + +/* \b bracket */ +static const char *eqn_backet(tblock *res, const char *inp, + const int mline, const style sty) +{ + const char *end; + tblock *r1; + + end=skip_to_next(inp); + if (*inp!=')') + return NULL; + { + r1=cvt_eqn(inp, end, mline, sty); + res->add("\\left("); + res->add(*r1); + res->add("\\right)"); + delete(r1); + } + return end; +} + +/* \l group */ +static const char *eqn_list(tblock *res, const char *inp, + const int mline, const style sty) +{ + tblock *r1; + const char *end; + + end=skip_to_next(inp); + if (*inp!=')') + return NULL; + { + r1=cvt_eqn(inp, end, mline, sty); + res->add("{"); + res->add(*r1); + res->add("}"); + delete(r1); + } + return end; +} + +/* \o overlay */ +static const char *eqn_overlay(tblock *res, const char *inp, + const int mline, const style sty) +{ + const char *end; + tblock *r1; + + end=skip_to_next(inp); + if (*inp!=')') + return NULL; + { + r1=cvt_eqn(inp, end, mline, sty); + res->add("\\smash{"); + res->add(*r1); + res->add("}"); + delete(r1); + } + return end; +} + +/* \r root */ +static const char *eqn_root(tblock *res, const char *inp, + const int mline, const style sty) + +{ + tblock *r1, *r2; + const char *mid, *end; + + mid=skip_to_next(inp); + switch (*mid) + { + case ',': + end=skip_to_next(mid+1); + if (*end!=')') + return NULL; + + r1=cvt_eqn(inp, mid, mline, style_map[sty][Op_Cramp]); + r2=cvt_eqn(mid+1, end, mline, style_map[sty][Op_Cramp]); + res->add("\\sqrt["); res->add(*r1); + res->add("]{"); // TeX syntax + res->add(*r2); + res->add('}'); + delete(r1); + delete(r2); + break; + + case ')': + r1=cvt_eqn(inp, mid, mline, style_map[sty][Op_Cramp]); + res->add("\\sqrt{"); + res->add(*r1); + res->add(*r1); + res->add('}'); + delete(r1); + break; + + default: + break; + } + return NULL; +} + +/* \f fraction */ +static const char *eqn_fract(tblock *res, const char *inp, + const int mline, const style sty) +{ + tblock *r1, *r2; + const char *mid, *end; + + mid=skip_to_next(inp); + if (*mid!=',') + return NULL; + + end=skip_to_next(mid+1); + if (*end!=')') + return NULL; + + 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(" \\over "); // TeX syntax + res->add(*r2); + res->add('}'); + delete(r1); + delete(r2); + + return end; +} + + +/* Anything I do not understand */ +const char *eqn_default(tblock *res, const char *inp, const char *end, + const int mline, const style sty) +{ + tblock *r1; + + res->add("{\\text{\tt \\backslash "); + res->add(inp, end-inp+1); + inp=end+1; + do + { + end=skip_to_next(inp); + r1=cvt_eqn(inp, end, mline, sty); + res->add(*r1); + if (*end!='\0') + res->add(*end); + else + res->add("{\\it EOF}"); + delete(r1); + inp=end+1; + } while (*end!='\0' && *end!=')'); + res->add("}} "); + + return end; +} + +/* 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; + const char *mid, *end; + int l, i; + + typedef const char *(*eqn_proc)(tblock *, const char *, const int, + const style); + static const struct { const char *name; eqn_proc func; } eqp[]= + { + { "b", eqn_backet }, + { "l", eqn_list }, + { "o", eqn_overlay }, + { "r", eqn_root }, + { "f", eqn_fract }, + { NULL, NULL }, + }; + + res=new(tblock); + while (inp<stop) + { + if (isspace(*inp) && *inp!='\n') + { + inp++; + continue; + } + + switch (*inp) + { + case '\0': + return res; + + case '\n': + if (mline) + res->add(" \\\\\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<<"cvt_eqn saw \\\\0\n"; + return res; // Safety. + + case '{': + res->add(" \\{"); // More guesswork + break; + + case '}': + res->add(" \\}"); // More guesswork + break; + + default: + mid=inp; + for (mid=inp; !isspace(*mid) && *mid!='('; mid++) ; + for (end=mid; *end!='('; end++) + { + if (*end=='\0') + break; + } + for (i=0; (unsigned) i<N(eqp); i++) + { + if (eqp[i].name==NULL) + { + inp=eqn_default(res, inp, end, mline, sty); + break; + } + l=strlen(eqp[i].name); + if (l!=mid-inp) + continue; + if (strncasecmp(eqp[i].name, inp, l)==0) + { + if ((inp=(*(eqp[i].func))(res, end+1, + mline, sty))!=NULL) + break; + } + } + break; + } + break; + case '+': + case '-': + res->add(*inp); + break; + case '*': + res->add("\\times "); + break; + + case ' ': + res->add("\\ "); + break; + + case '_': + res->add("\\hbox{\\_}"); + 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 (scn<stop && isdigit(*scn)) + scn++; // Skip number + if (*scn=='.') + { + scn++; + while (scn<stop && isdigit(*scn)) + scn++; // Hanlde decimals number + } + + /* Now start looking at what comes next */ + while (scn<stop) + { + if (isspace(*scn)) + { + scn++; + continue; + } + if (isupper(*scn) || islower(*scn)) + flg=1; + else + flg=0; + break; + } + } + + /* + * This section is meant to catch strings and render them nicely + * in a mbox. + */ + if (islower(*inp) || isupper(*inp) || flg) + { + res->add("\\text{"); + if (flg) // If flag set then add everything up to scn + { + while (inp<scn) + { + res->add(*inp); + inp++; + } + } + + flg=0; // Re-use flg + while (inp<stop && (islower(*inp) || isupper(*inp) + || isspace(*inp) + || *inp=='_' + || *inp=='^')) + { + if (isspace(*inp)) + { + flg=1; + inp++; + continue; // If space, just set the flag + } + if (flg) + res->add(' '); // 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 latex_data *dp; + tblock *cvt, eqn, *op; + const char *s; + int mline; + + dp=(struct latex_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 latex_data *dp; + + fmt=fmt; + out=out; + dp=(struct latex_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 (++open<close) + entry.add(*open); + if (dp->last_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 ltx_embed(const tok_seq::tok *t, const docfmt *fmt, FILE *out, + void *d) +{ + int i; + + for (i=0; (unsigned) i<N(emb); i++) + { + if (strncmp(t->data.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); +} |