/*
** tr2latex - troff to LaTeX converter
** COPYRIGHT (C) 1987 Kamal Al-Yahya, 1991,1992 Christian Engel
**
** Module: subs.c
**
** These subroutines do (in general) small things for the translator.
** They appear in alphabetical order and their names are unique in the
** first six characters.
*/
/*
** get single option
*/
int get_option(char *pin, char *w) {
char c;
int i, j;
for (j=0; *pin == ',' || *pin == ' ' || *pin == '\t'; j++, pin++);
for (i = 0; (c = *pin++) != EOS &&
(c != ' ' && c != '\t' && c != ',' && c != ';' && c != '(') && i < MAXWORD; i++) {
w[i] = c;
}
w[i] = EOS;
return (j+i);
}
/*
** get table options until ';'
*/
int get_tbl_options(char *pin, struct optstr *options)
{
char line[MAXLINE], *cp, nb[25], *t;
struct optstr *lp;
int c, ci, len = 0, found;
char opt[MAXWORD];
//tmp[0] = EOS;
for (lp = options; lp->optnam; lp++)
*(lp->optadd) = 0;
tab = '\t'; /* default is tab char */
len = get_line(pin, line, 0);
if (strchr(line, ';') == 0)
return(0);
cp = line;
while ((c = *cp) != ';') {
cp += get_option(cp, opt);
found = 0;
for (lp = options; lp->optadd; lp++) {
if (strcmp(lp->optnam, opt) == 0) {
*(lp->optadd) = 1;
while (*cp == ' ') cp++;
t = nb;
if (*cp == '(') {
while ((ci = *++cp) != ')')
*t++ = ci;
cp++;
}
*t++ = 0; *t = 0;
if (lp->optadd == &tab) {
if (nb[0])
*(lp->optadd) = nb[0];
} else
if (lp->optadd == &linsize) {
*(lp->optadd) = atoi(nb);
} else
if (lp->optadd == &DELIM1) {
DELIM1 = nb[0];
DELIM2 = nb[1];
}
found = 1;
break;
}
}
if (!found)
fprintf(stderr, "Illigel option in table definition: %s\n", opt);
}
return(len);
}
/*
** translate table
** arguments:
** pin
** pout
** offset amount to offset pin
*/
char *do_table (char *pin, char *pout, int *offset)
{
char w[MAXLINE+1], ww[MAXLINE+1], format[MAXWORD+1], tmp[MAXLINE+1];
char *ptr;
int i, fc = 0, columns = 0;
tmp[0] = EOS;
ptr = pin; /* remember where we started */
pin += get_tbl_options(pin, options);
if (boxflag || dboxflag || allflag)
format[fc++] = '|';
if (dboxflag)
format[fc++] = '|';
pin = skip_line(pin);
while (*pin != EOS) { /* get the LAST format line */
pin += get_line(pin, w, 0);
if (w[strlen(w) - 1] == '.')
break;
else /* not a format line */
pin = skip_line(pin);
}
for (i = 0; w[i] != '.'; i++) {
switch (w[i]) {
case ' ':
case '\t':
continue;
case 'l':
case 'L':
case 'n':
case 'N':
case 'a':
case 'A':
format[fc++] = 'l';
break;
case 'r':
case 'R':
format[fc++] = 'r';
break;
case 'c':
case 'C':
case 's':
case 'S':
format[fc++] = 'c';
break;
case '|':
format[fc++] = '|';
break;
case ',':
fc = 0; /* use only last format */
columns = 0;
continue;
default:
continue;
}
if (allflag)
format[fc++] = '|';
columns++;
}
if ((boxflag || dboxflag) && !allflag)
format[fc++] = '|';
if (dboxflag)
format[fc++] = '|';
if (columns == 0) {
fprintf (stderr, "Sorry, I cannot do tables without a format line\n"
"Doing plain translation of table, lines will be commented\n"
"You need to fix it yourself\n");
while (*pin != EOS) {
(void) getword (pin, w);
if (strcmp (w,".TE") == 0) {
pin += 4;
break;
}
pin += get_line (pin, w, 1);
*pout++ = '%';
pout = strapp (pout, w);
pout = strapp (pout, "\n");
pin++; /* skip the \n */
}
*offset = pin - ptr;
return (pout);
}
format[fc] = EOS;
pin = skip_line(pin);
pout = strapp(pout, "\\par\\noindent\n");
if (linsize > 0) {
snprintf(tmp, sizeof(tmp), "{\\arrayrulewidth=%dpt\n", linsize);
pout = strapp(pout, tmp);
}
if (ctrflag)
pout = strapp(pout, "\\begin{center}\n");
snprintf(tmp, sizeof(tmp), "\\begin{tabular}{%s}\n", format);
pout = strapp (pout, tmp);
if (boxflag || dboxflag || allflag)
pout = strapp(pout, "\\hline\n");
if (dboxflag)
pout = strapp(pout, "\\hline\n");
while (*pin != EOS) {
(void)getword(pin, w);
if (strcmp(w, ".sp") == 0) {
pin += get_line(pin, ww, 1);
snprintf(tmp, sizeof(tmp), "%s\n\\\\ ", ww);
pout = strapp(pout, tmp);
continue;
} else if (strcmp(w, "_") == 0) {
pout = strapp(pout, "\\hline\n");
pin = skip_line(pin);
continue;
} else if (strcmp(w, "=") == 0) {
pout = strapp(pout, "\\hline\n\\hline\n");
pin = skip_line(pin);
continue;
} else if (strcmp(w, "\n") == 0) {
pin++;
continue;
}
for (i = 0; i < columns - 1; i++) {
(void) getword (pin, w);
if (strcmp (w, ".TE") == 0) {
pin += 4;
if (i == 0 && !boxflag && !dboxflag && !allflag) {
pout -= 3; /* take back the \\ and the \n */
pout = strapp(pout, "\n");
}
if (boxflag)
pout = strapp(pout, "\\hline\n");
if (dboxflag)
pout = strapp(pout, "\\hline\n");
pout = strapp(pout,"\\end{tabular}\n");
if (ctrflag)
pout = strapp(pout, "\\end{center}\n");
if (linsize > 0)
pout = strapp(pout, "}\n");
pout = strapp(pout, "\\par\n");
*offset = pin - ptr;
return (pout);
}
(void)get_line(pin, w, 0);
if (strncmp(w, "T{", 2) == 0) {
pin = skip_line(pin);
pin += get_tbl_txt_entry(pin, w);
troff_tex(w, ww, 0, 0);
snprintf(tmp, sizeof(tmp), "\\parbox[t]{%5.4f\\hsize}{\n%s} & ", 1.0 / columns, ww);
pin += get_table_entry(pin, w, tab);
}
else {
pin += get_table_entry(pin, w, tab);
troff_tex(w, ww, 0, 1);
snprintf(tmp, sizeof(tmp), "%s & ", ww);
}
pin++; /* skip tab */
pout = strapp(pout,tmp);
} /* end for */
pin += skip_white(pin);
(void) getword (pin, w);
if (strcmp(w, ".TE") == 0) {
fprintf(stderr, "Oops! I goofed. I told I you I am not very good at tables\n"
"I've encountered an unexpected end for the table\n"
"You need to fix it yourself\n");
pin = skip_line(pin);
if (boxflag || allflag)
pout = strapp(pout, "\\hline\n");
if (dboxflag)
pout = strapp(pout, "\\hline\n");
pout = strapp(pout,"\\end{tabular}\n");
if (ctrflag)
pout = strapp(pout, "\\end{center}\n");
if (linsize > 0)
pout = strapp(pout, "}\n");
pout = strapp(pout, "\\par\n");
*offset = pin - ptr;
return(pout);
}
//pin += skip_white(pin);
(void)get_line(pin, w, 0);
if (strncmp(w, "T{", 2) == 0) {
pin = skip_line(pin);
pin += get_tbl_txt_entry(pin, w);
troff_tex(w, ww, 0, 0);
snprintf(tmp, sizeof(tmp), "\\parbox[t]{%5.4f\\hsize}{\n%s} \\\\\n", 1.0 / columns, ww);
//pin += get_table_entry(pin, w, tab);
}
else {
pin += get_table_entry(pin, w, '\n');
troff_tex(w, ww, 0, 1);
snprintf(tmp, sizeof(tmp), "%s \\\\\n", ww);
}
pin++; /* skip tab */
pout = strapp (pout, tmp);
if (allflag)
pout = strapp(pout, "\\hline\n");
}
fprintf (stderr, "Oops! I goofed. I told I you I am not very good at tables\n"
"File ended and I haven't finished the table!\n"
"You need to fix it yourself\n");
*offset = pin - ptr;
pout = strapp (pout, "\\end{tabular}\n\\par\n");
return (pout);
}
/*
** end current environment
*/
char *end_env (char *pout)
{
if (IP_stat[RSRE]) {
IP_stat[RSRE] = 0;
pout = strapp (pout, "\\end{IPlist}");
}
if (QP_stat) {
QP_stat = 0;
pout = strapp (pout, "\\end{quotation}");
}
if (TP_stat) {
TP_stat = 0;
pout = strapp (pout, "\\end{TPlist}");
}
return(pout);
}
/*
** set flag for current environment
*/
void envoke_stat (int par)
{
switch(par) {
case 2:
IP_stat[RSRE] = 1;
break;
case 3:
TP_stat = 1;
break;
case 4:
QP_stat = 1;
break;
default:
break;
}
}
/*
** do the flipping
*/
char * flip (char *pout, char *w)
{
int lb=0, rb=0;
char ww[MAXWORD+1], tmp[MAXWORD+1];
ww[0] = EOS;
tmp[0] = EOS;
pout--;
while (isspace (*pout))
pout--;
while (1) {
if (*pout == '{') {
lb++;
if (lb > rb)
break;
}
if (*pout == '}')
rb++;
if (rb == 0) {
if (! isspace (*pout) && *pout != '$') {
pout--;
continue;
}
else
break;
}
pout--;
if (lb == rb && lb != 0)
break;
}
pout++;
if (*pout == '\\') {
pout++;
(void) getword (pout, tmp);
snprintf(ww, sizeof(ww), "\\%s", tmp);
pout--;
}
else if (*pout == '{')
(void) get_brace_arg (pout, ww);
else
(void) getword (pout, ww);
*pout = EOS;
snprintf(tmp,sizeof(tmp),"\\%s %s", w, ww);
pout = strapp (pout, tmp);
return (pout);
}
/*
** take care of things like x hat under
*/
char * flip_twice (char *pout, char *w, char *ww)
{
int lb=0, rb=0;
char tmp1[MAXWORD+1], tmp2[MAXWORD+1];
/*
** get argument
** arguments:
** rec=1 means recursive
*/
int get_arg (register char *pin, char *w, int rec)
{
int c,len,i;
char ww[MAXWORD+1];
int delim;
int escape = 0;
len=0;
while ((c = *pin) == ' ' || c == '\t') { /* skip spaces and tabs */
pin++;
len++;
}
i = 0;
if (*pin == '{' || *pin == '\"') {
if (*pin == '{')
delim = '}';
else
delim = '\"';
pin++;
len++;
while ((c = *pin++) != EOS && (escape || c != delim) && i < MAXWORD) {
/*if (c == ' ' && delim == '\"')
ww[i++] = '\\';*/
if (escape && c == 't')
ww[i++] = '\t';
else
ww[i++] = (char)c;
if (c == '\\' && !escape)
escape = 1;
else {
escape = 0;
}
len++;
}
len++;
}
else {
while ((c = *pin++) != EOS && !isspace(c)
/* && c != '$' && c != '}' */ && i < MAXWORD) {
if (math_mode && c == '~')
break;
ww[i++] = (char)c;
len++;
}
}
ww[i] = EOS;
if (rec == 1) /* check if recursion is required */
troff_tex(ww, w, 1, 1);
else
strcpy(w, ww);
return(len);
}
/*
** get all arguments
** arguments:
** rec=1 means recursive
*/
int get_allargs (register char *pin, char ***ppw, int rec)
{
int c, i;
static char *ww [MAXARGS];
char w[MAXWORD+1], *instart;
int nww;
int delim;
instart = pin;
for (nww = 0; ; nww++) {
while ((c = *pin) == ' ' || c == '\t') /* skip spaces and tabs */
pin++;
if (c == '\n') {
pin++;
ww [nww] = EOS;
break;
}
ww [nww] = pin;
i=0;
if (*pin == '{' || *pin == '\"') {
if (*pin == '{')
delim = '}';
else
delim = '\"';
ww [nww] = ++pin;
while ((c = *pin++) != EOS && c != delim && i < MAXWORD)
/* EMPTY */
;
pin [-1] = EOS;
}
else {
while ((c = *pin++) != EOS && !isspace(c)
/* && c != '$' && c != '}' */ && i < MAXWORD) {
if (math_mode && c == '~')
break;
}
pin [-1] = EOS;
if (c == '\n') {
ww [nww + 1] = EOS;
break;
}
}
}
if (rec == 1) { /* check if recursion is required */
for (i = 0; ww [i]; i++) {
if (ww [i] && *ww [i]) {
troff_tex (ww [i], w, 1, 1);
if (strcmp (ww [i], w) != 0)
ww [i] = strdup(w);
}
}
}
*ppw = ww;
return (pin - instart);
}
/*
** get argument surrounded by braces
*/
void get_brace_arg (char *buf, char *w)
{
int c,i, lb=0, rb=0;
i=0;
while ((c = *buf++) != EOS) {
w[i++] = (char)c;
if (c == '{') lb++;
if (c == '}') rb++;
if (lb == rb) break;
}
w[i] = EOS;
}
/*
** get "define" or .de word
** arguments:
** pin delimited by space only
** w delimited by space only
*/
int get_defword (char *pin, char *w, int *illegal)
{
int c,i;
*illegal = 0;
for (i=0; (c = *pin++) != EOS && !isspace (c) && i < MAXWORD; i++) {
w[i] = (char)c;
if (isalpha(c) == 0)
*illegal = 1; /* illegal TeX macro */
}
w[i] = EOS;
if (*illegal == 0 && is_forbid(w) >= 0)
*illegal=1;
return(i);
}
/*
** get the rest of the line
** arguments:
** rec=1 means recursion is required
*/
int get_line (char *pin, char *w, int rec)
{
int c,i,len;
int escape=0;
char ww[MAXLINE+1];
i=0;
len=0;
c = *pin;
while ((c = *pin++) != EOS && c != '\n' && len < MAXLINE) {
if (de_arg > 0 && !rec && c == '\\' && !escape)
escape = 1;
else {
escape = 0;
ww[i++] = (char)c;
}
len++;
}
ww[i] = EOS;
if (de_arg>0 && ww[0] == '.') {
/* skip blanks */
for (i=1; ww[i] == ' '; i++);
strcpy(ww+1, ww+i);
}
//fprintf(stderr, "get_line:%s\n", ww);
if (rec == 1)
troff_tex(ww, w, 0, 1);
else
strcpy(w, ww);
//fprintf(stderr, "get_line out:%s\n", w);
return(len);
}
/*
** get multi-line argument
*/
int get_multi_line (char *pin, char *w)
{
int len=0,l=0,lines=0;
char tmp[MAXWORD+1];
int c1,c2;
w[0] = EOS; tmp[0] = EOS;
while (*pin != EOS) {
c1 = *pin;
c2 = *++pin;
--pin;
if (c1 == '.' && isupper(c2))
break;
lines++;
if (lines > 1)
strcat(w," \\\\\n");
l = get_line(pin,tmp,1);
strcat(w,tmp);
len += l+1;
pin += l+1;
}
len--;
pin--;
return(len);
}
/*
** get the macro substitution
*/
int get_mydef (char *pin, char *w)
{
int c1,c2,l,len;
char tmp[MAXLINE+1];
char ww[MAXLINE*20+1];
if (units == 'p')
strcpy (PARAMETER->units, "pt");
else if (units == 'i')
strcpy (PARAMETER->units, "in");
else if (units == 'c')
strcpy (PARAMETER->units, "cm");
else if (units == 'm')
strcpy (PARAMETER->units, "em");
else if (units == 'n') {
value = .5*value; /* n is about half the width of m */
strcpy (PARAMETER->units, "em");
}
else if (units == 'v')
strcpy(PARAMETER->units,"ex");
else if (units == 0) {
if (sign == 0 || PARAMETER->old_units[0] == EOS)
strcpy(PARAMETER->units,PARAMETER->def_units);
else
strcpy(PARAMETER->units,PARAMETER->old_units);
}
else {
fprintf(stderr,"unknown units %c, using default units\n", units);
strcpy(PARAMETER->units,PARAMETER->def_units);
}
if (sign == 0)
PARAMETER->value = value;
else
PARAMETER->value = PARAMETER->old_value + sign*value;
}
}
/*
** get the rest of the line -- Nelson Beebe
** arguments:
** rec=1 means recursion is required
*/
int get_string (char *pin, char *w, int rec)
{
int c,i,len;
char ww[MAXLINE+1];
char *start;
if (*pin != '\"')
return(get_line(pin,w,rec));
start = pin; /* remember start so we can find len */
i=0;
pin++; /* point past initial quote */
while ((c = *pin++) != EOS && c != '\"' && c != '\n' && i < MAXLINE)
ww[i++] = (char)c;
ww[i] = EOS;
if (c != '\n') /* flush remainder of line */
while ((c = *pin++) != '\n')
/* EMPTY */
;
len = pin - start - 1; /* count only up to NL, not past */
if (rec == 1)
troff_tex(ww,w,0,1);
else
strcpy(w,ww);
return(len);
}
/*
** get the argument for sub and sup
*/
int get_sub_arg (char *pin, char *w)
{
int c,len,i;
char ww[MAXWORD+1], tmp[MAXWORD+1];
len=0; tmp[0] = EOS;
while ((c = *pin) == ' ' || c == '\t') {
pin++;
len++;
}
i=0;
while ((c = *pin++) != EOS && c != ' ' && c != '\t' && c != '\n'
&& c != '$' && c != '}' && c != '~' && i < MAXWORD) {
ww[i++] = (char)c;
len++;
}
ww[i] = EOS;
if (strcmp(ww,"roman") == 0 || strcmp(ww,"bold") == 0
|| strcmp(w,"italic") == 0) {
(void) get_arg(pin,tmp,0);
snprintf(ww, sizeof(ww), "%s%c%s", ww, c, tmp);
len += strlen(tmp)+1;
}
troff_tex(ww,w,0,1); /* recursive */
return(len);
}
/*
**
*/
int get_table_entry (char *pin, char *w, int tab)
{
int i=0, escape=0;
char c;
while ((c = *pin++) != EOS && (escape || (c != tab && c != '\n')) && i < MAXLINE) {
if (escape && c != '\n')
w[i++] = '\\';
if (c == '&')
w[i++] = '\\';
if (c == '\\' && !escape)
escape = 1;
else {
w[i++] = c;
escape = 0;
}
}
w[i] = EOS;
return(i);
}
int get_tbl_txt_entry(char *pin, char *w) {
int i;
char c, tmp[MAXWORD+1];
for (i = 0; (c = *pin++) != EOS && i < MAXLINE; i++) {
w[i] = c;
if (c == '\n') {
(void)get_line(pin, tmp, 0);
if (strncmp(tmp, "T}", 2) == 0) {
w[++i] = EOS;
return (i + 2);
}
}
}
w[i] = EOS;
return (i);
}
/*
** get characters till the next space
*/
int get_till_space (char *pin, char *w)
{
int c,i;
for (i=0; (c = *pin++) != EOS && c != ' ' && c != '\n'
&& c != '\t' && i < MAXWORD; i++)
w[i] = (char)c;
w[i] = EOS;
return(i);
}
/*
** get the define substitution
*/
int getdef (char *pin, char *ww)
{
int c,i,len;
int def_delim;
char w[MAXWORD+1];
def_delim = *pin++; /* take first character as delimiter */
len=1;
i=0;
while ((c = *pin++) != EOS && c != def_delim && i < MAXWORD) {
len++;
w[i++] = (char)c;
}
w[i] = EOS;
len++;
if (c != def_delim) {
fprintf(stderr,
"WARNING: missing right delimiter in define, define=%s\n",w);
len--;
}
troff_tex(w,ww,0,1); /* now translate the substitution */
return(len);
}
/*
** get an alphanumeric word (dot also)
*/
int getword (char *pin, char *w)
{
int c,i;
for (i=0; (c = *pin++) != EOS
&& (isalpha(c) || isdigit(c) || c == '.') && i < MAXWORD; i++)
w[i] = (char)c;
if (i == 0 && c != EOS)
w[i++] = (char)c;
w[i] = EOS;
return(i);
}
/*
** check if w was defined by the user
*/
int is_def (char *w)
{
int i;
for (i=0; i < def_count; i++) {
if (strcmp(def[i].def_macro,w) == 0)
return(i);
}
return(-1);
}
/*
** check if w is in the flip list
*/
int is_flip (char *w)
{
int i;
for (i=0; i < flip_count; i++) {
if (strcmp(flip_list[i],w) == 0)
return(i);
}
return(-1);
}
/*
** check if w is one of those sacred macros
*/
int is_forbid (char *w)
{
int i;
for (i=0; i < forbd_count; i++) {
if (strcmp(forbid[i],w) == 0)
return(i);
}
return(-1);
}
/*
** check if w has a simple correspondence in TeX
*/
int is_mathcom (char *w, char *ww)
{
int i;
for (i = 0; i < mathcom_count; i++)
if (strcmp (math[i].troff_symb, w) == 0) {
strcpy (ww, math[i].tex_symb);
return (i);
}
return (-1);
}
/*
**
*/
int is_special (char *w, char *ww)
{
int i;
//fprintf(stderr, "special_count:%d\n", special_count);
for (i = 0; i < special_count; i++)
if (strcmp (special[i].troff_char, w) == 0) {
strcpy (ww, special[i].tex_char);
//fprintf(stderr, "Special: %d, %s -> %s\n", i, w, ww);
return (i);
}
return (-1);
}
/*
** check if w is user-defined macro
*/
int is_mydef (char *w)
{
int i;
for (i=0; i < mydef_count; i++) {
if (strcmp(mydef[i].def_macro,w) == 0)
return(i);
}
return(-1);
}
/*
** check if w is a macro or plain troff command
*/
int is_troff_mac (char *w, char *ww, int *arg, int *par)
{
int i;
for (i=0; i < macro_count; i++)
if (strcmp(macro[i].troff_mac,w) == 0) {
strcpy(ww,macro[i].tex_mac);
*arg = macro[i].arg;
*par = macro[i].macpar;
return(i);
}
return(-1);
}
/*
**
*/
void parse_units (char *ww, int *sign, int *units, float *value)
{
int len, k=0, i;
char tmp[MAXWORD+1];
len = strlen(ww);
if (ww[0] == '-')
*sign = -1;
else if (ww[0] == '+')
*sign = 1;
if (*sign != 0)
k++;
i=0;
while (k < len) {
if (isdigit(ww[k]) || ww[k] == '.')
tmp[i++] = ww[k++];
else
break;
}
tmp[i] = EOS;
sscanf(tmp,"%f",value);
i=0;
if (k < len) {
*units = ww[k++];
if (k < len)
fprintf(stderr, "Suspect problem in parsing %s, unit used is %c\n",
ww, *units);
}
}
/*
** check if w is in the similar list
*/
int similar (char *w)
{
int i;
for (i=0; i < sim_count ; i++) {
if (strcmp(sim_list[i],w) == 0)
return(1);
}
return(-1);
}
/*
** ignore the rest of the line
*/
char * skip_line (char *pin)
{
while (*pin != '\n' && *pin != EOS)
pin++;
if (*pin == EOS)
return(pin);
else
return(++pin);
}
/*
** skip white space
*/
int skip_white (char *pin)
{
int c,len=0;
while ((c = *pin++) == ' ' || c == '\t') /* || c == '\n') */
len++;
return(len);
}
/*
** copy tail[] to s[], return ptr to terminal EOS in s[]
*/
char * strapp (char *s, char *tail)
{
while ((*s++ = *tail++) != 0)
if (debug_o)
fputc(s[-1], stderr);
return (s-1); /* pointer to EOS at end of s[] */
}