/* ** 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" 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)); /* ** alternate fonts (manual macro) */ char *alternate (char *pin, char *pout, char *w) { int which = 1; char font[MAXWORD], font1[MAXWORD], font2[MAXWORD], ww[MAXWORD], tmp[MAXWORD]; 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) { sprintf(tmp,"{%s %s}", font1, ww); which = 2; } else { sprintf (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); } /* ** translate table ** arguments: ** pin ** pout ** offset amount to offset pin */ char *do_table (char *pin, char *pout, int *offset) { char w [MAXWORD], ww [MAXWORD], format [MAXWORD], tmp [MAXWORD]; char *ptr; int i, len, columns=0; int tab = '\t'; /* default tab */ tmp[0] = EOS; ptr = pin; /* remember where we started */ len = get_line (pin, w, 0); if (w [strlen (w) - 1] == ';') { /* options */ pin += len; if (strncmp (w, "tab", 3) == 0) /* get the tab charecter */ tab = w[4]; /* expect something like tab(&); */ pin = skip_line(pin); } while (*pin != EOS) { /* get the LAST format line */ len = get_line (pin, w, 0); if (w[strlen (w) - 1] != '.') /* not a format line */ break; pin += len; for (i = 0; i < len - 1; i++) { if (isspace (w[i])) continue; if (w[i] == 'l') format[columns] = 'l'; else if (w[i] == 'r') format[columns] = 'r'; else format[columns] = 'c'; columns++; } } 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[columns] = EOS; sprintf (tmp, "\\par\n\\begin{tabular}{%s}\n",format); pout = strapp (pout, tmp); while (*pin != EOS) { for (i = 0; i < columns - 1; i++) { (void) getword (pin, w); if (i == 0 && (strcmp (w, "\n") == 0 || strcmp (w, "_") == 0)) { pin++; i--; continue; } if (strcmp (w, ".TE") == 0) { pin += 4; if (i == 0) { pout -= 3; /* take back the \\ and the \n */ *pout = EOS; } pout = strapp(pout,"\n\\end{tabular}\n\\par\n"); *offset = pin - ptr; return (pout); } pin += get_table_entry(pin,w,tab); pin ++; /* skip tab */ troff_tex(w,ww,0,1); sprintf(tmp,"%s & ",ww); pout = strapp(pout,tmp); } (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\nI've encountered an unexpected end for the table\n\ You need to fix it yourself\n"); pin += 4; pout = strapp(pout,"\\end{tabular}\n\\par\n"); *offset = pin - ptr; return(pout); } pin += get_table_entry(pin,w,'\n'); pin++; /* skip tab */ troff_tex(w,ww,0,1); pout = strapp (pout, ww); pout = strapp (pout, "\\\\\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) { IP_stat = 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 = 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], tmp[MAXWORD]; 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); sprintf (ww, "\\%s", tmp); pout--; } else if (*pout == '{') (void) get_brace_arg (pout, ww); else (void) getword (pout, ww); *pout = EOS; sprintf (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], tmp2[MAXWORD]; 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); sprintf(tmp1,"\\%s",tmp2); pout--; } else if (*pout == '{') (void) get_brace_arg(pout,tmp1); else (void) getword(pout,tmp1); *pout = EOS; sprintf(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]; int delim; 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 && c != delim && i < MAXWORD) { if (c == ' ' && delim == '\"') ww[i++] = '\\'; ww[i++] = (char)c; 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], *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] = strsave (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; char ww[MAXLINE]; i=0; len=0; while ((c = *pin++) != EOS && c != '\n' && len < MAXLINE) { ww[i++] = (char)c; len++; } ww[i] = EOS; if (rec == 1) troff_tex(ww,w,0,1); else strcpy(w,ww); return(len); } /* ** get multi-line argument */ int get_multi_line (char *pin, char *w) { int len=0,l=0,lines=0; char tmp[MAXWORD]; 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[MAXWORD]; tmp[0] = EOS; len=1; while (*pin != EOS) { c1 = *pin; c2 = *++pin; --pin; if (c1 == '.' && c2 == '.') break; l = get_line(pin,tmp,1); strcat(w,tmp); len += l+1; pin += l+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]; 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], tmp1[MAXWORD], tmp2[MAXWORD]; 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]; 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) { register int c,i,len; char ww[MAXLINE]; register 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], tmp[MAXWORD]; 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); sprintf(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 c, i=0; for (i=0; (c = *pin++) != EOS && c != tab && i < MAXWORD; i++) w[i] = (char)c; 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]; 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); } /* ** 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]; 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 (register char *s, register char *tail) { while ((*s++ = *tail++) != 0) if (debug_o) fputc(s[-1], stderr); return (s-1); /* pointer to EOS at end of s[] */ } /* ** copy input to buffer, buffer holds only MAXLEN characters */ void tmpbuf (FILE *in, char *buffer) { int c; unsigned int l=0; while (l++ < MAXLEN && (c = getc(in)) != EOF) *buffer++ = (char) c; if (l >= MAXLEN) { fprintf (stderr,"Sorry: document is too large\n"); exit(-1); } *buffer = EOS; } /* ** save a string by allocating space */ char *strsave (char *s) { char *res; if ((res = malloc (strlen (s) + 1)) == NULL) { fprintf (stderr, "strsave: Can't allocate %d bytes\n", strlen(s) + 1); errexit (errno); } strcpy (res, s); return (res); }