/*
** 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.
*/

#include        "setups.h"
#include        "protos.h"
#include        "simil.h"
#include        "greek.h"
#include        "flip.h"
#include        "forbid.h"
#include        "maths.h"
#include        "macros.h"
#include        "special.h"

int get_tbl_txt_entry(char *pin, char *w);

extern int def_count;
extern int mydef_count;

/* compile-time counting of elements */
const int GRK_count = (sizeof(GRK_list) / sizeof(GRK_list[0]));
const int sim_count = (sizeof(sim_list) / sizeof(sim_list[0]));
const int flip_count = (sizeof(flip_list) / sizeof(flip_list[0]));
const int forbd_count = (sizeof(forbid) / sizeof(forbid[0]));
const int mathcom_count = (sizeof(math) / sizeof(struct math_equiv));
const int macro_count = (sizeof(macro) / sizeof(struct macro_table));
const int special_count = (sizeof(special) / sizeof(struct special_table));

/*
** alternate fonts (manual macro)
*/
char *alternate(char *pin, char *pout, char *w)
{
       int which = 1;
       char font[MAXWORD + 1], font1[MAXWORD + 1], font2[MAXWORD + 1], ww[MAXWORD + 1], tmp[MAXWORD + 1];

       tmp[0] = EOS;
       switch (w[1]) {
       case 'R':       strcpy(font1, "\\rm"); break;
       case 'I':       strcpy(font1, "\\it"); break;
       case 'B':       strcpy(font1, "\\bf"); break;
       }
       switch (w[2]) {
       case 'R':       strcpy(font2, "\\rm"); break;
       case 'I':       strcpy(font2, "\\it"); break;
       case 'B':       strcpy(font2, "\\bf"); break;
       }

       strcpy(font, font1);
       while (*pin != '\n' && *pin != EOS) {
               pin += get_arg(pin, ww, 1);
               if (which == 1) {
                       snprintf(tmp,sizeof(tmp),"{%s %s}", font1, ww);
                       which = 2;
               }
               else {
                       snprintf(tmp,sizeof(tmp),"{%s %s}", font2, ww);
                       which = 1;
               }
               pout = strapp(pout, tmp);
               while (*pin == ' ' || *pin == '\t')
                       pin++;
       }
       return (pout);
}



/*
** check if w is in the GREEK list
*/
int CAP_GREEK(char *w)
{
       int i;

       for (i = 0; i < GRK_count; i++) {
               if (strcmp(GRK_list[i], w) == 0)
                       return (1);
       }
       return (-1);
}

int prefix(char *small, char *big)
{
       char c;
       while ((c = *small++) == *big++)
               if (c == EOS)
                       return (1);
       return (c == EOS);
}

int expflag, ctrflag, boxflag, dboxflag, tab, linsize, allflag, DELIM1, DELIM2;

struct optstr {
       char *optnam;
       int *optadd;
};
struct optstr options[] = {
       { "tab",                &tab },
       { "TAB",                &tab },
       { "allbox",             &allflag },
       { "ALLBOX",             &allflag },
       { "box",                &boxflag },
       { "BOX",                &boxflag },
       { "center",             &ctrflag },
       { "CENTER",             &ctrflag },
       { "delim",              &DELIM1 },
       { "DELIM",              &DELIM1 },
       { "doublebox",  &dboxflag },
       { "DOUBLEBOX",  &dboxflag },
       { "expand",             &expflag },
       { "EXPAND",             &expflag },
       { "linesize",   &linsize },
       { "LINESIZE",   &linsize },
       { EOS,                  0 }
};

/*
** 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];

       tmp1[0] = EOS;          tmp2[0] = EOS;
       pout--;
       while (*pout == ' ' || *pout == '\t' || *pout == '\n')
               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,tmp2);
               snprintf(tmp1, sizeof(tmp1), "\\%s", tmp2);
               pout--;
       }
       else if (*pout == '{')
               (void) get_brace_arg(pout,tmp1);
       else
               (void) getword(pout,tmp1);
       *pout = EOS;
       snprintf(tmp2, sizeof(tmp2), "\\%s{\\%s %s}", w, ww, tmp1);
       pout = strapp(pout,tmp2);
       return(pout);
}



/*
** 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];

       tmp[0] = EOS;
       ww[0] = EOS;
       len=1;
       while (*pin != EOS) {
               c1 = *pin;
               c2 = *++pin;
               --pin;
               if (c1 == '.' && c2 == '.')
                       break;
               l = get_line(pin, tmp, 0);
               if (len+l+1 < MAXLINE*20) {
                       strcat(ww, tmp);
                       strcat(ww, "\n");
                       len += l+1;
                       pin += l+1;
               } else break;
       }
       troff_tex(ww, w, 0, 1);
       return(len);
}


/*
** get N lines
*/
int get_N_lines (char *pin, char *w, int N)
{
       int len=0,l=0,lines=0;
       char tmp[MAXWORD+1];

       w[0] = EOS;     tmp[0] = EOS;
       while (*pin != EOS && lines < N) {
               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 text surrounded by quotes in math mode
*/
int get_no_math (char *pin, char *w)
{
       int c,i,len;

       len = 0;
       for (i=0; (c = *pin++) != EOS && c != '\"' && i < MAXWORD; i++) {
               if (c == '{' || c == '}') {
                       w[i] = '\\';
                       w[++i] = (char)c;
               }
               else
                       w[i] = (char)c;
               len++;
       }
       w[i] = EOS;
       return(len);
}


/*
** get the denominator of over
*/
char *get_over_arg (char *pin, char *ww)
{
       char w[MAXWORD+1], tmp1[MAXWORD+1], tmp2[MAXWORD+1];
       int len;

       w[0] = EOS;
       tmp1[0] = EOS;
       tmp2[0] = EOS;
       pin += getword (pin,tmp1);              /* read first word */
       pin += skip_white (pin);
       len = getword (pin, tmp2);              /* read second word */
       strcat(w,tmp1); strcat(w," ");

       /* as long as there is a sup or sub read the next two words */
       while (strcmp (tmp2, "sub") == 0 || strcmp (tmp2, "sup") == 0) {
               pin += len;
               strcat (w, tmp2);
               strcat (w, " ");
               pin += skip_white (pin);
               pin += getword (pin, tmp1);
               strcat (w, tmp1);
               strcat (w, " ");
               pin += skip_white (pin);
               len = getword (pin, tmp2);
       }
       troff_tex (w, ww, 0, 1);
       return (pin);
}



/*
** get reference
*/
int get_ref (char *pin, char *w)
{
       int len=0, l=0, lines=0;
       char tmp[MAXWORD+1];

       w[0] = EOS;     tmp[0] = EOS;
       while (*pin != EOS) {
               if (*pin == '\n')
                       break;
               (void) getword(pin,tmp);
               if (tmp[0] == '.' && isupper(tmp[1])) {
                       /* these commands don't cause a break in reference */
                       if (strcmp (tmp, ".R") != 0 && strcmp (tmp, ".I") != 0
                               && strcmp(tmp,".B") != 0)
                               break;
               }
               else if (tmp[0] == '.' && !(isupper(tmp[1]))) {
                       /* these commands don't cause a break in reference */
                       if (strcmp (tmp, ".br") != 0 && strcmp (tmp, ".bp") != 0)
                               break;
               }
               l = get_line (pin, tmp, 1);
               lines++;
               if (lines > 1)
                       strcat (w, " ");
               strcat (w, tmp);
               len += l+1;
               pin += l+1;
       }
       len--;
       pin--;
       return (len);
}


/*
**
*/
void get_size (char *ww, struct measure *PARAMETER)
{
       int sign=0, units=0;
       float value;

       if (ww[0] == EOS) {
               if (PARAMETER->def_value == 0) {
                       PARAMETER->value = PARAMETER->old_value;
                       strcpy(PARAMETER->units,PARAMETER->old_units);
               }
               else {
                       PARAMETER->value = PARAMETER->def_value;
                       strcpy(PARAMETER->units,PARAMETER->def_units);
               }
       }
       else {
               PARAMETER->old_value = PARAMETER->value;
               strcpy (PARAMETER->old_units, PARAMETER->units);

               parse_units (ww, &sign, &units, &value);

               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);
}



/*
** change GREEK to Greek
*/
void GR_to_Greek (char *w, char *ww)
{
       *ww++ = '\\';
       *ww++ = *w;
       while(*++w != EOS)
               *ww++ = tolower(*w);
       *ww = EOS;
}



/*
** 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[] */
}