home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
word2x0a.zip
/
source
/
latex-embed.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1998-04-20
|
10KB
|
546 lines
/* $Id: latex-embed.cc,v 1.12 1997/04/17 20:03:19 dps Exp $ */
/* Embed handling for *TeX output */
#include <stdio.h>
#include <string.h>
#include <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);
}