/* $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);
}