rs@uunet.UU.NET (Rich Salz) (07/02/87)
Mod.Sources: Volume 10, Number 32 Submitted by: Kamal Al-Yahya <kamal@hanauma.stanford.edu> Archive-name: tr2latex This program translates troff documents to latex. You will notice that the translation is not always 100%, but it relieves one from manual translation, where the user might need to touch up on the translated document to customize the translation. There is a testfile and a manual page in the package that can be used to test the translator. Try some UNIX manual pages too. #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # tr2tex.c # tr.c # subs.c # setups.h # simil.h # greek.h # flip.h # forbid.h # macros.h # maths.h # makefile # makefile.msc # troffms.sty # troffman.sty # tr2tex.9 # tr2tex.9-tex-orig # README # testfile # testfile.tex-orig # diffs.tex # This archive created: Sun Mar 8 12:05:26 1987 export PATH; PATH=/bin:$PATH if test -f 'tr2tex.c' then echo shar: will not over-write existing file "'tr2tex.c'" else cat << \SHAR_EOF > 'tr2tex.c' /* COPYRIGHT (C) 1987 Kamal Al-Yahya */ /* tr2tex: troff to tex translator */ /* Author: Kamal Al-Yahya, Stanford University, 9/4/86 */ /* Last modified: 1/1/87 */ /* Keyword: convert translate tex troff */ char *documentation[] = { " SYNTAX", " tr2tex [-m] file1 file2 ...", "or", " tr2tex [-m] < file1 file2 ...", "", " Use the -m flag for manual", "", }; int doclength = { sizeof documentation/sizeof documentation[0] }; #include "setups.h" #ifdef tops20 #define TEMPFILE "texXXXXXX" #else #define TEMPFILE "/tmp/texXXXXXX" #endif FILE *out_file; #if HAVE_SGTTY struct sgttyb ttystat; #endif extern char *mktemp(); char scratch_file[MAXWORD]; int man; int xargc; char **xargv; int main(argc,argv) int argc; char *argv[]; { char *inbuf, *outbuf; FILE *temp,*scr; register char *cptr; int piped_in; int i; long timeval; /* clock value from time() for ctime() */ char *document = "article"; /* document type */ char *options = "[troffms,11pt]"; /* style options */ /* Allocate large arrays dynamically to conserve stack space */ if (((inbuf = (char *)malloc(MAXLEN*sizeof(char))) == (char *)NULL) || ((outbuf = (char *)malloc(MAXLEN*sizeof(char))) == (char *)NULL)) { fprintf(stderr,"tr2tex: Cannot malloc() internal buffer space\n\ Need two arrays of %d characters each\n",MAXLEN); exit(-1); } /* If no arguments, and not in a pipeline, self document */ #if HAVE_SGTTY piped_in = ioctl ((fileno (stdin)), TIOCGETP, &ttystat); #else /* if no sggty, it cannot distinguish piped input from no input */ piped_in = (argc == 1); #endif if (argc == 1 && !piped_in) { for( i=0; i<doclength; i++) printf("%s\n",documentation[i]); exit (0); } /* initialize spacing and indentation parameters */ strcpy(linespacing.def_units,"\\normalbaselineskip"); strcpy(linespacing.old_units,"\\normalbaselineskip"); strcpy(indent.def_units,"em"); strcpy(indent.old_units,"em"); strcpy(tmpind.def_units,"em"); strcpy(tmpind.old_units,"em"); strcpy(space.def_units,"\\baselineskip"); strcpy(space.old_units,"\\baselineskip"); strcpy(vspace.def_units,"pt"); strcpy(vspace.old_units,"pt"); linespacing.value = 1.; linespacing.old_value = 1.; indent.value = 0.; indent.old_value = 0.; tmpind.value = 0.; tmpind.old_value = 0.; space.value = 1.; space.old_value = 1.; vspace.value = 1.; vspace.old_value = 1.; linespacing.def_value = 0; indent.def_value = 0; tmpind.def_value = 0; space.def_value = 1; vspace.def_value = 1; out_file = stdout; /* default output */ math_mode = 0; /* start with non-math mode */ de_arg = 0; /* not a .de argument */ /* process option flags */ xargc = argc; xargv = argv; for (xargc--,xargv++; xargc; xargc--,xargv++) { cptr = *xargv; if( *cptr=='-' ) { while( *(++cptr)) { switch( *cptr ) { case 'm': man = 1; strcpy(options,"[troffman]"); break; default: fprintf(stderr, "tr2tex: unknown flag -%c\n",*cptr); break; } } } } /* start of translated document */ timeval = time(0); fprintf(out_file,"%% -*-LaTeX-*-\n\ %% Converted automatically from troff to LaTeX by tr2tex on %s",ctime(&timeval)); fprintf(out_file,"%% tr2tex was written by Kamal Al-Yahya at Stanford University\n\ %% (Kamal%%Hanauma@SU-SCORE.ARPA)\n\n\n"); /* document style and options */ fprintf(out_file,"\\documentstyle%s{%s}\n\\begin{document}\n",options,document); /* first process pipe input */ if(piped_in) { /* need to buffer; can't seek in pipes */ /* make a temporary and volatile file */ strcpy(scratch_file,TEMPFILE); mktemp(scratch_file); if ((scr=fopen(scratch_file,"w")) == (FILE *)NULL) { fprintf(stderr, "tr2tex: Cannot open scratch file [%s]\n",scratch_file); exit(-1); } scrbuf(stdin,scr); fclose(scr); scr=fopen(scratch_file,"r"); unlink(scratch_file); tmpbuf(scr,inbuf); fclose(scr); troff_tex(inbuf,outbuf,0,0); fprintf(out_file,"%%\n%% input file: stdin\n%%\n"); fputs(outbuf,out_file); } /* then process input line for arguments and assume they are input files */ xargc = argc; xargv = argv; for (xargc--,xargv++; xargc; xargc--,xargv++) { cptr = *xargv; if( *cptr=='-' ) continue; /* this is a flag */ if((temp=fopen(cptr,"r")) != (FILE *)NULL) { tmpbuf(temp,inbuf); fclose(temp); troff_tex(inbuf,outbuf,0,0); fprintf(out_file,"%%\n%% input file: %s\n%%\n",cptr); fputs(outbuf,out_file); } else fprintf(stderr,"tr2tex: Cannot open %s\n",cptr); } /* close translated document */ fputs("\\end{document}\n",out_file); exit(0); } SHAR_EOF fi # end of overwriting check if test -f 'tr.c' then echo shar: will not over-write existing file "'tr.c'" else cat << \SHAR_EOF > 'tr.c' /* COPYRIGHT (C) 1987 Kamal Al-Yahya */ /* This program has the HARD-WIRED rules of the translator. It should handled with care. */ #define IN_TR 1 #include "setups.h" int def_count = 0; int mydef_count = 0; void troff_tex(inbuf,outbuf,mid,rec) char *inbuf,*outbuf; int mid,rec; { char eqn_no[MAXWORD], w[MAXWORD], ww[MAXLINE], tmp[MAXWORD], tmp2[MAXWORD]; char *p; int len,c,c1,c2,i,j; int ref = 0; int put_brace = 0; int first_word = 1; int no_word = 1; int arg = 0; int par = 0; int illegal = 0; int floating = 0; static int delim_defd = 0; /* whether math delimiter has been defined */ static char *DELIM = "$"; float flen; int N; int RSRE = 0; /* block indentation */ int thisfont = 1; /* default font is roman */ int lastfont = 1; /* default last font is roman */ int offset = 0; /* amount to offset inbuf */ extern man; /* man flag */ *outbuf = NULL; w[0] = NULL; ww[0] = NULL; tmp[0] = NULL; tmp2[0] = NULL; while (*inbuf != NULL) { len = getword(inbuf,w); c1 = *--inbuf; c2 = *++inbuf; inbuf += len; if (isspace(w[0]) == 0) no_word = 0; /* first check if we are in math mode */ if (math_mode) { len = get_till_space(inbuf,ww); sprintf(tmp,"%s%s",w,ww); if (strcmp(w,"delim") == 0) { delim_defd = 1; inbuf += skip_white(inbuf); DELIM[0] = *inbuf; inbuf = skip_line(inbuf); } /* check if it is a math delimiter; switch to non-math mode if so */ else if (delim_defd && strcmp(w,DELIM) == 0) { math_mode = 0; *outbuf++ = '$'; } /* check for illegal macros here */ else if (len > 0 && def_count > 0 && (i=is_def(tmp)) >= 0) { inbuf += len; outbuf = strapp(outbuf,def[i].replace); } /* See if it is a (legally) defined macro */ else if (def_count > 0 && (i=is_def(w)) >= 0) { if (def[i].illegal) outbuf = strapp(outbuf,def[i].replace); else { outbuf = strapp(outbuf,"\\"); outbuf = strapp(outbuf,w); } } /* Search for commands in some order; start with non-alphanumeric symbols */ else if (strcmp(w,"#") == 0 || strcmp(w,"&") == 0 || strcmp(w,"%") == 0 || strcmp(w,"_") == 0) { outbuf = strapp(outbuf,"\\"); outbuf = strapp(outbuf,w); } else if (strcmp(w,"=") == 0) { if (*inbuf == '=') { inbuf++; outbuf = strapp(outbuf,"\\equiv"); } else outbuf = strapp(outbuf,"="); } else if (strcmp(w,"<") == 0 || strcmp(w,">") == 0) { if (*inbuf == '=') { inbuf++; if (strcmp(w,"<") == 0) outbuf = strapp(outbuf,"\\le"); else outbuf = strapp(outbuf,"\\ge"); } } else if (strcmp(w,"-") == 0) { if (*inbuf == '>') { inbuf++; outbuf = strapp(outbuf,"\\to"); } else if (*inbuf == '+') { inbuf++; outbuf = strapp(outbuf,"\\mp"); } else *outbuf++ = '-'; } else if (strcmp(w,"+") == 0) { if (*inbuf == '-') { inbuf++; outbuf = strapp(outbuf,"\\pm"); } else *outbuf++ = '+'; } else if (strcmp(w,"\"") == 0) { len = get_no_math(inbuf,ww); inbuf += len+1; if (len > 1) { sprintf(tmp,"\\ \\it\\hbox{%s}",ww); outbuf = strapp(outbuf,tmp); } else if (len == 1) *outbuf++ = ww[0]; } /* Now search for symbols that start with a captial */ else if (strcmp(w,".EN") == 0) { math_mode = 0; if ((len=strlen(eqn_no)) > 0) { sprintf(tmp,"\\eqno %s",eqn_no); outbuf = strapp(outbuf,tmp); } eqn_no[0] = NULL; c1 = *--outbuf; c2 = *--outbuf; if (c1 == '\n' && c2 == '$') *--outbuf = NULL; else { outbuf += 2; outbuf = strapp(outbuf,"$$"); } } /* Now search for symbols that start with a small letter */ else if (strcmp(w,"bold") == 0 || strcmp(w,"roman") == 0 || strcmp(w,"italic") == 0) { inbuf += get_arg(inbuf,ww,1); if (strcmp(w,"bold") == 0) { sprintf(tmp,"{\\bf %s}",ww); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,"roman") == 0) { sprintf(tmp,"{\\rm %s}",ww); outbuf = strapp(outbuf,tmp); } else { sprintf(tmp,"{\\it %s}",ww); outbuf = strapp(outbuf,tmp); } } else if (strcmp(w,"define") == 0) { if (def_count >= MAXDEF) { fprintf(stderr, "Too many defines. MAXDEF=%d\n",MAXDEF); exit(-1); } for (i=0; *--outbuf != '$' && i < MAXLEN; i++) tmp[i] = *outbuf; tmp[i] = NULL; strcat(tmp,"$$"); *--outbuf = NULL; inbuf += skip_white(inbuf); inbuf += get_defword(inbuf,w,&illegal); inbuf += skip_white(inbuf); inbuf += getdef(inbuf,ww); if (illegal) { def[def_count].illegal = 1; fprintf(stderr, "illegal TeX macro, %s, replacing it\n",w); p = (char *)malloc((unsigned)(strlen(ww)+1)* sizeof(char)); strcpy(p,ww); def[def_count].replace = p; } else { def[def_count].illegal = 0; sprintf(tmp2,"\\def\\%s{%s}\n",w,ww); outbuf = strapp(outbuf,tmp2); } p = (char *)malloc((unsigned)(strlen(w)+1)*sizeof(char)); strcpy(p,w); def[def_count++].def_macro = p; inbuf += skip_white(inbuf); for (j=i+1; j >= 0; j--) *outbuf++ = tmp[j]; tmp[0] = NULL; } else if (strcmp(w,"gsize") == 0 || strcmp(w,"gfont") == 0) inbuf = skip_line(inbuf); else if (strcmp(w,"left") == 0 || strcmp(w,"right") == 0) { sprintf(tmp,"\\%s",w); outbuf = strapp(outbuf,tmp); inbuf += skip_white(inbuf); len = getword(inbuf,ww); if (strcmp(ww,"floor") == 0) { inbuf += len; if (strcmp(w,"left") == 0) outbuf = strapp(outbuf,"\\lfloor"); else outbuf = strapp(outbuf,"\\rfloor"); } else if (strcmp(ww,"nothing") == 0 || ww[0] == '\"') { inbuf += len; *outbuf++ = '.'; if (ww[0] == '\"') inbuf++; } else if (*inbuf == '{' || *inbuf == '}') *outbuf++ = '\\'; } else if (strcmp(w,"over") == 0) { if (!first_word) { outbuf--; for (i=0; *outbuf == ' ' || *outbuf == '\t' || *outbuf =='\n'; i++) tmp[i] = *outbuf--; if (*outbuf == '}' && put_brace == 0) *outbuf = ' '; else { for (; !(*outbuf == ' ' || *outbuf == '\t' || *outbuf =='\n' || *outbuf == '$'); i++) tmp[i] = *outbuf--; put_brace = 0; *++outbuf = '{'; } for (j=i-1; j >= 0; j--) *++outbuf = tmp[j]; *++outbuf = NULL; } outbuf = strapp(outbuf,"\\over"); inbuf += skip_white(inbuf); *outbuf++ = ' '; if (*inbuf == '{') inbuf++; else { inbuf = get_over_arg(inbuf,ww); outbuf = strapp(outbuf,ww); if (*inbuf != NULL || !first_word) *outbuf++ = '}'; } } else if (strcmp(w,"size") == 0) inbuf += get_arg(inbuf,ww,0); else if (strcmp(w,"sup") == 0 || strcmp(w,"to") == 0 || strcmp(w,"sub") == 0 || strcmp(w,"from") == 0) { while ((c = *--outbuf) == ' ' || c == '\t' || c == '\n') ; *++outbuf = NULL; if (strcmp(w,"sup") == 0 || strcmp(w,"to") == 0) outbuf = strapp(outbuf,"^"); else outbuf = strapp(outbuf,"_"); inbuf += skip_white(inbuf); len = get_sub_arg(inbuf,ww); inbuf += len; if (len > 1) { sprintf(tmp,"{%s}",ww); outbuf = strapp(outbuf,tmp); len = skip_white(inbuf); inbuf += len; (void) getword(inbuf,ww); if (strcmp(ww,"over") == 0) put_brace = 1; inbuf -= len; } else outbuf = strapp(outbuf,ww); } else if (strcmp(w,"up") == 0 || strcmp(w,"down") == 0 || strcmp(w,"fwd") == 0 || strcmp(w,"back") == 0) { if (strcmp(w,"up") == 0) { outbuf = strapp(outbuf,"\\raise"); strcpy(tmp,"ex"); } else if (strcmp(w,"down") == 0) { outbuf = strapp(outbuf,"\\lower"); strcpy(tmp,"ex"); } else if (strcmp(w,"fwd") == 0) { outbuf = strapp(outbuf,"\\kern"); strcpy(tmp,"em"); } else if (strcmp(w,"back") == 0) { outbuf = strapp(outbuf,"\\kern-"); strcpy(tmp,"em"); } inbuf += skip_white(inbuf); inbuf += getword(inbuf,ww); len = atoi(ww); flen = len/100.; ww[0] = NULL; sprintf(tmp2,"%4.2f%s",flen,tmp); outbuf = strapp(outbuf,tmp2); } /* Now check if the word is a member of a group */ else if (CAP_GREEK(w) > 0) { GR_to_Greek(w,ww); outbuf = strapp(outbuf,ww); } else if (is_flip(w) >= 0) { if (!first_word) { len = skip_white(inbuf); inbuf += len; (void) getword(inbuf,ww); if (is_flip(ww) >= 0) { inbuf += strlen(ww); outbuf = flip_twice(outbuf,w,ww); } else { inbuf -= len; outbuf = flip(outbuf,w); } } else { outbuf = strapp(outbuf,"\\"); outbuf = strapp(outbuf,w); } } else if (is_mathcom(w,ww) >=0 ) outbuf = strapp(outbuf,ww); else if (similar(w) > 0) { outbuf = strapp(outbuf,"\\"); outbuf = strapp(outbuf,w); } /* if none of the above math commands matched, it is an ordinary symbol; just copy it */ else outbuf = strapp(outbuf,w); } /* check if it is a math delimiter; switch to math mode if so */ else if (strcmp(w,"$") == 0 && de_arg > 0) { de_arg++; *outbuf++ = '#'; } else if (delim_defd && strcmp(w,DELIM) == 0) { math_mode = 1; *outbuf++ = '$'; } else if (strcmp(w,"$") == 0) outbuf = strapp(outbuf,"\\$"); /* check if it is a non-math troff command */ else if ((c2 == '.') && !(mid) && (c1 == '\n' || (first_word))) { /* Search in some order; start with non-alphanumeric characters */ if (strcmp(w,".") == 0) { c1 = *inbuf; c2 = *++inbuf; if (c1 == '\\' && c2 == '\"') { ++inbuf; inbuf += get_line(inbuf,ww,0); outbuf = strapp(outbuf,"%"); outbuf = strapp(outbuf,ww); } else { fprintf(stderr, "I cannot translate troff macro .%c%c\n",c1,c2); inbuf += get_line(inbuf,ww,0); sprintf(tmp,"%%.%c%c",c1,c2); outbuf = strapp(outbuf,tmp); outbuf = strapp(outbuf,ww); if (*inbuf == NULL) *outbuf++ = '\n'; } } /* Now search for commads that start with a capital */ else if (strcmp(w,".AB") == 0) { inbuf += get_arg(inbuf,ww,0); if (strcmp(ww,"no") == 0) outbuf = strapp(outbuf,"\\bigskip"); else outbuf = strapp(outbuf,"\\begin{abstract}"); } else if (strcmp(w,".B") == 0 || strcmp(w,".bf") == 0 || strcmp(w,".I") == 0 || strcmp(w,".it") == 0 || strcmp(w,".R") == 0 || strcmp(w,".rm") == 0) { if (strcmp(w,".R") == 0 || strcmp(w,".rm") == 0) strcpy(w,"rm"); else if (strcmp(w,".B") == 0 || strcmp(w,".bf") == 0) strcpy(w,"bf"); else strcpy(w,"it"); inbuf += get_arg(inbuf,ww,1); if (ww[0] == NULL) { outbuf = strapp(outbuf,"\\"); outbuf = strapp(outbuf,w); } else { sprintf(tmp,"{\\%s %s}",w,ww); outbuf = strapp(outbuf,tmp); } } else if (man && (strcmp(w,".BR") == 0 || strcmp(w,".BI") == 0 || strcmp(w,".IR") == 0 || strcmp(w,".IB") == 0 || strcmp(w,".RI") == 0 || strcmp(w,".RB") == 0)) { outbuf = alternate(inbuf,outbuf,w); inbuf = skip_line(inbuf); *outbuf++ = '\n'; } else if (strcmp(w,".BX") == 0) { inbuf += get_arg(inbuf,ww,1); sprintf(tmp,"\\fbox{%s}",ww); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".EQ") == 0) { math_mode = 1; put_brace = 0; outbuf = strapp(outbuf,"$$"); len = get_arg(inbuf,eqn_no,0); if (strcmp(eqn_no,"I") == 0 || strcmp(eqn_no,"L") == 0) { fprintf(stderr,"lineups are ignored\n"); inbuf += len; len = get_arg(inbuf,eqn_no,0); } if ((strlen(eqn_no)) > 0) inbuf += len; len = get_arg(inbuf,tmp,0); if (strcmp(tmp,"I") == 0 || strcmp(tmp,"L") == 0) { fprintf(stderr,"lineups are ignored\n"); inbuf += len; } } else if (strcmp(w,".IP") == 0) { inbuf += get_arg(inbuf,ww,1); inbuf = skip_line(inbuf); if (IP_stat == 0) outbuf = strapp(outbuf,"\\begin{itemize}\n"); sprintf(tmp,"\\item[{%s}]\n",ww); outbuf = strapp(outbuf,tmp); if (de_arg > 0) mydef[mydef_count].par = 2; else IP_stat = 1; } else if (strcmp(w,".KE") == 0) { if (floating) outbuf = strapp(outbuf,"\\end{figure}"); else outbuf = strapp(outbuf,"}"); floating = 0; } else if (strcmp(w,".KF") == 0) { floating = 1; outbuf = strapp(outbuf,"\\begin{figure}"); } else if (strcmp(w,".QP") == 0) { if (de_arg > 0) mydef[mydef_count].par = 4; else QP_stat = 1; outbuf = strapp(outbuf,"\\begin{quotation}"); } else if (strcmp(w,".RE") == 0) { RSRE--; if (RSRE < 0) fprintf(stderr,".RS with no matching .RE\n"); sprintf(tmp,"\\ind{%d\\parindent}",RSRE); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".RS") == 0) { RSRE++; sprintf(tmp,"\\ind{%d\\parindent}",RSRE); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".Re") == 0) { if (ref == 0) outbuf = strapp(outbuf,"\\REF\n"); ref++; inbuf = skip_line(inbuf); inbuf += get_ref(inbuf,ww); sprintf(tmp,"\\reference{%s}",ww); outbuf = strapp(outbuf,tmp); } else if (man && (strcmp(w,".TP") == 0 || strcmp(w,".HP") == 0)) { if (IP_stat && TP_stat) { outbuf = strapp(outbuf,"\\end{itemize}%\n"); IP_stat = 0; } if (QP_stat && TP_stat) { outbuf = strapp(outbuf,"\\end{quotation}%\n"); QP_stat = 0; } inbuf = skip_line(inbuf); inbuf += get_line(inbuf,ww,1); if (TP_stat == 0) { sprintf(tmp,"\\begin{TPlist}{%s}\n",ww); outbuf = strapp(outbuf,tmp); } sprintf(tmp,"\\item[{%s}]",ww); outbuf = strapp(outbuf,tmp); if (de_arg > 0) mydef[mydef_count].par = 3; else TP_stat = 1; } else if (man && (strcmp(w,".TH") == 0)) { /* expect something like .TH LS 1 "September 4, 1985"*/ outbuf = strapp(outbuf,"\\phead"); for (j = 1; j <= 3; ++j) { inbuf += get_arg(inbuf,ww,0); sprintf(tmp,"{%s}",ww); outbuf = strapp(outbuf,tmp); } *outbuf++ = '\n'; } else if (strcmp(w,".TS") == 0) { fprintf(stderr,"I am not very good at tables\n\ I can only do very simple ones. You may need to check what I've done\n"); inbuf = skip_line(inbuf); outbuf = do_table(inbuf,outbuf,&offset); inbuf += offset; offset = 0; /* reset */ } /* Now search for commands that start with small letters */ else if (strcmp(w,".TE") == 0) { fprintf(stderr,"Oops! I goofed. I told you I am not very good at tables.\nI have encountered a table end but I am not in table mode\n"); } else if (strcmp(w,".de") == 0) { de_arg = 1; if (mydef_count >= MAXDEF) { fprintf(stderr, "Too many .de's. MAXDEF=%d\n",MAXDEF); exit(-1); } inbuf += skip_white(inbuf); inbuf += get_defword(inbuf,w,&illegal); inbuf += skip_white(inbuf); inbuf += get_mydef(inbuf,ww); mydef[mydef_count].arg_no = de_arg; if (illegal) { mydef[mydef_count].illegal = 1; fprintf(stderr, "illegal TeX macro, %s, replacing it\n",w); p = (char *)malloc((unsigned)(strlen(ww)+2)* sizeof(char)); sprintf(p,"%s",ww); mydef[mydef_count].replace = p; } else { mydef[mydef_count].illegal = 0; sprintf(tmp,"\\def\\%s",w); outbuf = strapp(outbuf,tmp); for (j=1; j<de_arg; j++) { sprintf(tmp,"#%d",j); outbuf = strapp(outbuf,tmp); } sprintf(tmp,"{%s}\n",ww); outbuf = strapp(outbuf,tmp); } p = (char *)malloc((unsigned)(strlen(w)+2)*sizeof(char)); sprintf(p,".%s",w); mydef[mydef_count++].def_macro = p; inbuf = skip_line(inbuf); de_arg = 0; } else if (strcmp(w,".ds") == 0) { inbuf += get_arg(inbuf,w,0); inbuf += skip_white(inbuf); inbuf += get_line(inbuf,ww,1); if (strcmp(w,"LH") == 0) { sprintf(tmp,"\\lefthead{%s}",ww); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,"RH") == 0) { sprintf(tmp,"\\righthead{%s}",ww); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,"CF") == 0) { if (index(ww,'%') == 0) { sprintf(tmp,"\\footer{%s}",ww); outbuf = strapp(outbuf,tmp); } else outbuf = strapp(outbuf, "\\footer{\\rm\\thepage}"); } else { fprintf(stderr,"I do not understand .ds %s\n",w); sprintf(tmp,"%%.ds %s %s",w,ww); outbuf = strapp(outbuf,tmp); } } else if (strcmp(w,".sp") == 0) { inbuf += get_arg(inbuf,ww,0); (void) get_size(ww,&space); sprintf(tmp,"\\par\\vspace{%3.1f%s}", space.value,space.units); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".in") == 0) { inbuf += get_arg(inbuf,ww,0); (void) get_size(ww,&indent); sprintf(tmp,"\\ind{%3.1f%s}",indent.value,indent.units); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".ls") == 0) { inbuf += get_arg(inbuf,ww,0); (void) get_size(ww,&linespacing); sprintf(tmp,"\\baselineskip=%3.1f%s",linespacing.value, linespacing.units); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".so") == 0) { inbuf += get_arg(inbuf,ww,0); sprintf(tmp,"\\input %s",ww); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".ti") == 0) { inbuf += get_arg(inbuf,ww,0); tmpind.value = indent.value; strcpy(tmpind.units,indent.units); (void) get_size(ww,&tmpind); sprintf(tmp,"\\tmpind{%3.1f%s}", tmpind.value,tmpind.units); outbuf = strapp(outbuf,tmp); } else if (strcmp(w,".vs") == 0) { inbuf += get_arg(inbuf,ww,0); (void) get_size(ww,&vspace); sprintf(tmp,"\\par\\vspace{%3.1f%s}", vspace.value,vspace.units); outbuf = strapp(outbuf,tmp); } /* check if it is a member of a group */ else if (mydef_count > 0 && (i=is_mydef(w)) >= 0) { if (mydef[i].par > 0) { if (de_arg > 0) mydef[mydef_count].par = mydef[i].par; else { outbuf = end_env(outbuf); outbuf = strapp(outbuf,"\n"); } } if (mydef[i].illegal) outbuf = strapp(outbuf,mydef[i].replace); else { w[0] = '\\'; /* replace dot by backslash */ outbuf = strapp(outbuf,w); } for (j=1; j <mydef[i].arg_no; j++) { inbuf += get_arg(inbuf,ww,1); sprintf(tmp,"{%s}",ww); outbuf = strapp(outbuf,tmp); } if (de_arg == 0) envoke_stat(mydef[i].par); } else if ((i=is_troff_mac(w,ww,&arg,&par)) >= 0) { if (par > 0) { if (de_arg > 0) mydef[mydef_count].par = par; else outbuf = end_env(outbuf); } outbuf = strapp(outbuf,ww); if (ww[0] == NULL) inbuf = skip_line(inbuf); if (ww[0] != NULL && arg == 0) { inbuf = skip_line(inbuf); *outbuf++ = '\n'; } if (arg > 0) { if (arg == 1) { inbuf += skip_white(inbuf); inbuf += get_string(inbuf,ww,1); } else { if (isupper(w[1])) { inbuf = skip_line(inbuf); inbuf += get_multi_line(inbuf,ww); } else { inbuf += get_arg(inbuf,tmp,0); inbuf = skip_line(inbuf); if (tmp[0] == NULL) N = 1; else N = atoi(tmp); inbuf += get_N_lines(inbuf,ww,N); } } sprintf(tmp2,"{%s}",ww); outbuf = strapp(outbuf,tmp2); } } /* if none of the above commands matched, it is either an illegal macro or an unknown command */ else { len = get_till_space(inbuf,ww); sprintf(tmp,"%s%s",w,ww); if (mydef_count > 0 && (i=is_mydef(tmp)) >= 0) { inbuf += len; if (mydef[i].par > 0) { if (de_arg > 0) mydef[mydef_count].par=mydef[i].par; else { outbuf = end_env(outbuf); outbuf = strapp(outbuf,"\n"); } } outbuf = strapp(outbuf,mydef[i].replace); for (j=1; j <mydef[i].arg_no; j++) { inbuf += get_arg(inbuf,ww,1); sprintf(tmp,"{%s}",ww); outbuf = strapp(outbuf,tmp); } if (de_arg == 0) envoke_stat(mydef[i].par); } else { fprintf(stderr, "I cannot translate troff macro %s\n",w); inbuf += get_line(inbuf,ww,0); outbuf = strapp(outbuf,"%"); outbuf = strapp(outbuf,w); outbuf = strapp(outbuf,ww); if (*inbuf == NULL) *outbuf++ = '\n'; } } } /* some manuals have commented lines beginning with ''' */ else if ((c2 == '\'') && !(mid) && (c1 == '\n' || (first_word))) { if (*inbuf == '\'') { inbuf++; if (*inbuf == '\'') { inbuf++; outbuf = strapp(outbuf,"%"); } else outbuf = strapp(outbuf,"''"); } else outbuf = strapp(outbuf,"'"); } /* See if it is one of these symbols */ else if (strcmp(w,"#") == 0 || strcmp(w,"&") == 0 || strcmp(w,"{") == 0 || strcmp(w,"}") == 0 || strcmp(w,"%") == 0 || strcmp(w,"_") == 0 || strcmp(w,"~") == 0 || strcmp(w,"^") == 0 ) { outbuf = strapp(outbuf,"\\"); outbuf = strapp(outbuf,w); if (strcmp(w,"~") == 0 || strcmp(w,"^") == 0) outbuf = strapp(outbuf,"{}"); } else if (strcmp(w,">") == 0 || strcmp(w,"<") == 0 || strcmp(w,"|") == 0) { sprintf(tmp,"$%s$",w); outbuf = strapp(outbuf,tmp); } /* check for backslash commands */ else if (strcmp(w,"\\") == 0) { if (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n') { outbuf = strapp(outbuf,"\\"); *outbuf++ = *inbuf++; } else if (*inbuf == NULL) ; else if (*inbuf == '-') { inbuf++; outbuf = strapp(outbuf,"--"); } else if (*inbuf == '~' || *inbuf == '^') { inbuf++; outbuf = strapp(outbuf,"\\/"); } else if (*inbuf == '0') { inbuf++; outbuf = strapp(outbuf,"\\ "); } else if (*inbuf == 'e') { inbuf++; outbuf = strapp(outbuf,"\\bs "); } else if (*inbuf == '\\') { inbuf++; if (*inbuf == '$' && de_arg > 0) { inbuf++; de_arg++; *outbuf++ = '#'; } else outbuf = strapp(outbuf,"\\bs "); } else if (*inbuf == '`' || *inbuf == '\'') ; /* do nothing */ else if (*inbuf == '"') { inbuf++; inbuf += get_line(inbuf,ww,0); outbuf = strapp(outbuf,"%"); outbuf = strapp(outbuf,ww); } else if (*inbuf == '|') { inbuf++; outbuf = strapp(outbuf,"\\,"); } else if (*inbuf == '&') inbuf++; else if (*inbuf == '(') { c1 = *++inbuf; c2 = *++inbuf; inbuf++; if (c1 == 'e' && c2 == 'm') outbuf = strapp(outbuf,"---"); else if (c1 == 'd' && c2 == 'e') outbuf = strapp(outbuf,"$^\\circ$"); else fprintf(stderr, "I am not prepared to handle \\(%c%c\n",c1,c2); } else if (*inbuf == 's') inbuf +=3; else if (*inbuf == '*') { c1 = *++inbuf; inbuf++; if (c1 == ':') outbuf = strapp(outbuf,"\\\""); else if (c1 == 'C') outbuf = strapp(outbuf,"\\v"); else if (c1 == ',') outbuf = strapp(outbuf,"\\c"); else if (c1 != '(') { sprintf(tmp,"\\%c",c1); outbuf = strapp(outbuf,tmp); } else { fprintf(stderr, "I am not prepared to handle \\*( cases\n"); inbuf += 2; } if (c1 != '(') { c1 = *inbuf++; sprintf(tmp,"{%c}",c1); outbuf = strapp(outbuf,tmp); } } else if (*inbuf == 'f') { c1 = *++inbuf; inbuf++; if (c1 == '1' || c1 == 'R') { lastfont = thisfont; thisfont = 1; if (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n' || *inbuf == '\f') {*outbuf++ = ' '; inbuf++;} outbuf = strapp(outbuf,"%\n\\rm "); } else if (c1 == '2' || c1 == 'I') { lastfont = thisfont; thisfont = 2; if (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n' || *inbuf == '\f') {*outbuf++ = ' '; inbuf++;} outbuf = strapp(outbuf,"%\n\\it "); } else if (c1 == '3' || c1 == 'B') { lastfont = thisfont; thisfont = 3; if (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n' || *inbuf == '\f') {*outbuf++ = ' '; inbuf++;} outbuf = strapp(outbuf,"%\n\\bf "); } else if (c1 == 'P') { /* preserve white space - from Nelson Beebe */ if (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n' || *inbuf == '\f') {*outbuf++ = ' '; inbuf++;} switch(lastfont) { case 1: outbuf = strapp(outbuf,"\\rm%\n"); thisfont = 1; break; case 2: outbuf = strapp(outbuf,"\\it%\n"); thisfont = 2; break; case 3: outbuf = strapp(outbuf,"\\bf%\n"); thisfont = 3; break; default: outbuf = strapp(outbuf,"\\rm%\n"); thisfont = 1; break; } } else fprintf(stderr, "I do not understand \\f%c yet\n",c1); } else { fprintf(stderr,"I am not prepared to handle \\%c\n",*inbuf); inbuf++; } } /* if non of the above checks, its a dull word; copy it */ else outbuf = strapp(outbuf,w); *outbuf = NULL; ww[0] = NULL; tmp[0] = NULL; tmp2[0] = NULL; if (!no_word) first_word = 0; } /* if file end, close opened environments and delimitters */ if (rec == 0) { if (IP_stat) outbuf = strapp(outbuf,"\\end{itemize}\n"); if (QP_stat) outbuf = strapp(outbuf,"\\end{quotation}\n"); if (TP_stat) outbuf = strapp(outbuf,"\\end{TPlist}\n"); } *outbuf = NULL; } SHAR_EOF fi # end of overwriting check if test -f 'subs.c' then echo shar: will not over-write existing file "'subs.c'" else cat << \SHAR_EOF > 'subs.c' /* COPYRIGHT (C) 1987 Kamal Al-Yahya */ /* 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 "simil.h" #include "greek.h" #include "flip.h" #include "forbid.h" #include "maths.h" #include "macros.h" extern def_count; extern mydef_count; /* compile-time counting of elements */ int GRK_count = (sizeof(GRK_list)/sizeof(GRK_list[0])); int sim_count = (sizeof(sim_list)/sizeof(sim_list[0])); int flip_count = (sizeof(flip_list)/sizeof(flip_list[0])); int forbd_count = (sizeof(forbid)/sizeof(forbid[0])); int mathcom_count = (sizeof(math)/sizeof(struct math_equiv)); int macro_count = (sizeof(macro)/sizeof(struct macro_table)); char * alternate(inbuf,outbuf,w) /* alternate fonts (manual macro) */ char *inbuf, *outbuf, *w; { int f1,f2; int which=1; char font[MAXWORD], font1[MAXWORD], font2[MAXWORD], ww[MAXWORD], tmp[MAXWORD]; tmp[0] = NULL; f1 = w[1]; f2 = w[2]; if (f1 == 'R') strcpy(font1,"\\rm"); if (f1 == 'I') strcpy(font1,"\\it"); if (f1 == 'B') strcpy(font1,"\\bf"); if (f2 == 'R') strcpy(font2,"\\rm"); if (f2 == 'I') strcpy(font2,"\\it"); if (f2 == 'B') strcpy(font2,"\\bf"); strcpy(font,font1); while (*inbuf != '\n' && *inbuf != NULL) { inbuf += get_arg(inbuf,ww,1); sprintf(tmp,"{%s %s}",font,ww); outbuf = strapp(outbuf,tmp); if (which == 1) { which = 2; strcpy(font,font2); } else { which = 1; strcpy(font,font1); } while (*inbuf == ' ' || *inbuf == '\t') inbuf++; } return(outbuf); } int CAP_GREEK(w) /* check if w is in the GREEK list */ char *w; { int i; for (i=0; i < GRK_count ; i++) { if (strcmp(GRK_list[i],w) == 0) return(1); } return(-1); } char * do_table(inbuf,outbuf,offset) char *inbuf, *outbuf; int *offset; /* amount to offset inbuf */ { char w[MAXWORD], ww[MAXWORD], format[MAXWORD], tmp[MAXWORD]; char *ptr; int i,j,len,columns=0; int tab = '\t'; /* default tab */ tmp[0] = NULL; ptr = inbuf; /* remember where we started */ len = get_line(inbuf,w,0); if (w[strlen(w)-1] == ';') /* options */ { inbuf += len; if (strncmp(w,"tab",3) == 0) /* get the tab charecter */ tab = w[4]; /* expect something like tab(&); */ inbuf = skip_line(inbuf); } while (*inbuf != NULL) /* get the LAST format line */ { len = get_line(inbuf,w,0); if (w[strlen(w)-1] != '.') break; /* not a fromat line */ inbuf += len; for (i=0, j=0; i<len-1; i++) { if (isspace(w[i])) continue; columns++; if (w[i] == 'l') format[j] = 'l'; else if (w[i] == 'r') format[j] = 'r'; else format[j] = 'c'; j++; } } 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 (*inbuf != NULL) { (void) getword(inbuf,w); if (strcmp(w,".TE") == 0) {inbuf += 4; break;} inbuf += get_line(inbuf,w,1); *outbuf++ = '%'; outbuf = strapp(outbuf,w); outbuf = strapp(outbuf,"\n"); inbuf++; /* skip the \n */ } *offset = inbuf - ptr; return(outbuf); } format[j] = NULL; sprintf(tmp,"\\par\n\\begin{tabular}{%s}\n",format); outbuf = strapp(outbuf,tmp); while (*inbuf != NULL) { for (i=0; i<columns-1; i++) { (void) getword(inbuf,w); if (i == 0 && (strcmp(w,"\n") == 0 || strcmp(w,"_") == 0)) {inbuf++; i--; continue;} if (strcmp(w,".TE") == 0) { inbuf += 4; if (i == 0) { outbuf -= 3; /* take back the \\ and the \n */ *outbuf = NULL; } outbuf = strapp(outbuf,"\n\\end{tabular}\n\\par\n"); *offset = inbuf - ptr; return(outbuf); } inbuf += get_table_entry(inbuf,w,tab); inbuf ++; /* skip tab */ troff_tex(w,ww,0,1); sprintf(tmp,"%s & ",ww); outbuf = strapp(outbuf,tmp); } (void) getword(inbuf,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"); inbuf += 4; outbuf = strapp(outbuf,"\\end{tabular}\n\\par\n"); *offset = inbuf - ptr; return(outbuf); } inbuf += get_table_entry(inbuf,w,'\n'); inbuf++; /* skip tab */ troff_tex(w,ww,0,1); outbuf = strapp(outbuf,ww); outbuf = strapp(outbuf,"\\\\\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 = inbuf - ptr; outbuf = strapp(outbuf,"\\end{tabular}\n\\par\n"); return(outbuf); } char * end_env(outbuf) char *outbuf; { if (IP_stat) { IP_stat = 0; outbuf = strapp(outbuf,"\\end{itemize}"); } if (QP_stat) { QP_stat = 0; outbuf = strapp(outbuf,"\\end{quotation}"); } if (TP_stat) { TP_stat = 0; outbuf = strapp(outbuf,"\\end{TPlist}"); } return(outbuf); } void envoke_stat(par) int par; { switch(par) { case 2: IP_stat = 1; break; case 3: TP_stat = 1; break; case 4: QP_stat = 1; break; default: break; } } char * flip(outbuf,w) /* do the flipping */ char *outbuf, *w; { int lb=0, rb=0; char ww[MAXWORD], tmp[MAXWORD]; ww[0] = NULL; tmp[0] = NULL; outbuf--; while (*outbuf == ' ' || *outbuf == '\t' || *outbuf == '\n') outbuf--; while (1) { if (*outbuf == '{') { lb++; if (lb > rb) break; } if (*outbuf == '}') rb++; if (rb == 0) { if (*outbuf != ' ' && *outbuf != '\t' && *outbuf != '\n' && *outbuf != '$') { outbuf--; continue; } else break; } outbuf--; if (lb == rb && lb != 0) break; } outbuf++; if (*outbuf == '\\') { outbuf++; (void) getword(outbuf,tmp); sprintf(ww,"\\%s",tmp); outbuf--; } else if (*outbuf == '{') (void) get_brace_arg(outbuf,ww); else (void) getword(outbuf,ww); *outbuf = NULL; sprintf(tmp,"\\%s %s",w,ww); outbuf = strapp(outbuf,tmp); return(outbuf); } char * flip_twice(outbuf,w,ww) /* take care of things like x hat under */ char *outbuf, *w, *ww; { int lb=0, rb=0; char tmp1[MAXWORD], tmp2[MAXWORD]; tmp1[0] = NULL; tmp2[0] = NULL; outbuf--; while (*outbuf == ' ' || *outbuf == '\t' || *outbuf == '\n') outbuf--; while (1) { if (*outbuf == '{') { lb++; if (lb > rb) break; } if (*outbuf == '}') rb++; if (rb == 0) { if (*outbuf != ' ' && *outbuf != '\t' && *outbuf != '\n' && *outbuf != '$') { outbuf--; continue; } else break; } outbuf--; if (lb == rb && lb != 0) break; } outbuf++; if (*outbuf == '\\') { outbuf++; (void) getword(outbuf,tmp2); sprintf(tmp1,"\\%s",tmp2); outbuf--; } else if (*outbuf == '{') (void) get_brace_arg(outbuf,tmp1); else (void) getword(outbuf,tmp1); *outbuf = NULL; sprintf(tmp2,"\\%s{\\%s %s}",w,ww,tmp1); outbuf = strapp(outbuf,tmp2); return(outbuf); } int get_arg(inbuf,w,rec) /* get argumnet */ char *inbuf, *w; int rec; /* rec=1 means recursive */ { int c,len,i; char ww[MAXWORD]; int delim; len=0; while ((c = *inbuf) == ' ' || c == '\t') /* skip spaces and tabs */ {inbuf++; len++;} i=0; if (*inbuf == '{' || *inbuf == '\"') { if (*inbuf == '{') delim = '}'; else delim = '\"'; inbuf++; len++; while ((c = *inbuf++) != NULL && c != delim && i < MAXWORD) { if (c == ' ' && delim == '\"') ww[i++] = '\\'; ww[i++] = (char)c; len++; } len++; } else { while ((c = *inbuf++) != NULL && c != ' ' && c != '\t' && c != '\n' && c != '$' && c != '}' && i < MAXWORD) { if (math_mode && c == '~') break; ww[i++] = (char)c; len++; } } ww[i] = NULL; if (rec == 1) /* check if recursion is rquired */ troff_tex(ww,w,1,1); else strcpy(w,ww); return(len); } void get_brace_arg(buf,w) /* get argumnet surrounded by braces */ char *buf, *w; { int c,i, lb=0, rb=0; i=0; while ((c = *buf++) != NULL) { w[i++] = (char)c; if (c == '{') lb++; if (c == '}') rb++; if (lb == rb) break; } w[i] = NULL; } int get_defword(inbuf,w,illegal) /* get "define" or .de word */ char *inbuf, *w; /* delimited by space only */ int *illegal; { int c,i; *illegal = 0; for (i=0; (c = *inbuf++) != NULL && c != ' ' && c != '\n' && c != '\t' && i < MAXWORD; i++) { w[i] = (char)c; if (isalpha(c) == 0) *illegal = 1; /* illegal TeX macro */ } w[i] = NULL; if (*illegal == 0) if (is_forbid(w) >= 0) *illegal=1; return(i); } int get_line(inbuf,w,rec) /* get the rest of the line */ char *inbuf, *w; int rec; /* rec=1 means recursion is required */ { int c,i,len; char ww[MAXLINE]; i=0; len=0; while ((c = *inbuf++) != NULL && c != '\n' && len < MAXLINE) {ww[i++] = (char)c; len++;} ww[i] = NULL; if (rec == 1) troff_tex(ww,w,0,1); else strcpy(w,ww); return(len); } int get_multi_line(inbuf,w) /* get multi-line argument */ char *inbuf, *w; { int len=0,l=0,lines=0; char tmp[MAXWORD]; int c1,c2; w[0] = NULL; tmp[0] = NULL; while (*inbuf != NULL) { c1 = *inbuf; c2 = *++inbuf; --inbuf; if (c1 == '.' && isupper(c2)) break; lines++; if (lines > 1) strcat(w," \\\\\n"); l = get_line(inbuf,tmp,1); strcat(w,tmp); len += l+1; inbuf += l+1; } len--; inbuf--; return(len); } int get_mydef(inbuf,w) /* get the macro substitution */ char *inbuf, *w; { int c1,c2,l,len; char tmp[MAXWORD]; tmp[0] = NULL; len=1; while (*inbuf != NULL) { c1 = *inbuf; c2 = *++inbuf; --inbuf; if (c1 == '.' && c2 == '.') break; l = get_line(inbuf,tmp,1); strcat(w,tmp); len += l+1; inbuf += l+1; } return(len); } int get_N_lines(inbuf,w,N) /* get N lines */ char *inbuf, *w; int N; { int len=0,l=0,lines=0; char tmp[MAXWORD]; w[0] = NULL; tmp[0] = NULL; while (*inbuf != NULL && lines < N) { lines++; if (lines > 1) strcat(w," \\\\\n"); l = get_line(inbuf,tmp,1); strcat(w,tmp); len += l+1; inbuf += l+1; } len--; inbuf--; return(len); } int get_no_math(inbuf,w) /* get text surrounded by quotes in math mode */ char *inbuf, *w; { int c,i,len; len = 0; for (i=0; (c = *inbuf++) != NULL && c != '\"' && i < MAXWORD; i++) { if (c == '{' || c == '}') {w[i] = '\\'; w[++i] = (char)c;} else w[i] = (char)c; len++; } w[i] = NULL; return(len); } char * get_over_arg(inbuf,ww) /* get the denominator of over */ char *inbuf, *ww; { char w[MAXWORD], tmp1[MAXWORD], tmp2[MAXWORD]; int len; w[0] = NULL; tmp1[0] = NULL; tmp2[0] = NULL; inbuf += getword(inbuf,tmp1); /* read first word */ inbuf += skip_white(inbuf); len = getword(inbuf,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) { inbuf += len; strcat(w,tmp2); strcat(w," "); inbuf += skip_white(inbuf); inbuf += getword(inbuf,tmp1); strcat(w,tmp1); strcat(w," "); inbuf += skip_white(inbuf); len = getword(inbuf,tmp2); } troff_tex(w,ww,0,1); return(inbuf); } int get_ref(inbuf,w) /* get reference */ char *inbuf, *w; { int len=0, l=0, lines=0; char tmp[MAXWORD]; w[0] = NULL; tmp[0] = NULL; while (*inbuf != NULL) { if (*inbuf == '\n') break; (void) getword(inbuf,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(inbuf,tmp,1); lines++; if (lines > 1) strcat(w," "); strcat(w,tmp); len += l+1; inbuf += l+1; } len--; inbuf--; return(len); } void get_size(ww,PARAMETER) char *ww; struct measure *PARAMETER; { int sign=0, units=0; float value; if (ww[0] == NULL) { 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,&value,&units); 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] == NULL) strcpy(PARAMETER->units,PARAMETER->def_units); else strcpy(PARAMETER->units,PARAMETER->old_units); } else { fprintf(stderr,"unknown units %c, using default units\n"); strcpy(PARAMETER->units,PARAMETER->def_units); } if (sign == 0) PARAMETER->value = value; else PARAMETER->value = PARAMETER->old_value + sign*value; } } int get_string(inbuf,w,rec) /* get the rest of the line -- Nelson Beebe */ char *inbuf, *w; int rec; /* rec=1 means recursion is required */ { register int c,i,len; char ww[MAXLINE]; register char *start; if (*inbuf != '\"') return(get_line(inbuf,w,rec)); start = inbuf; /* remember start so we can find len */ i=0; inbuf++; /* point past initial quote */ while ((c = *inbuf++) != NULL && c != '\"' && c != '\n' && i < MAXLINE) ww[i++] = (char)c; ww[i] = NULL; if (c != '\n') /* flush remainder of line */ while ((c = *inbuf++) != '\n') /* NO-OP */; len = inbuf - start - 1; /* count only up to NL, not past */ if (rec == 1) troff_tex(ww,w,0,1); else strcpy(w,ww); return(len); } int get_sub_arg(inbuf,w) /* get the argument for sub and sup */ char *inbuf, *w; { int c,len,i; char ww[MAXWORD], tmp[MAXWORD]; len=0; tmp[0] = NULL; while ((c = *inbuf) == ' ' || c == '\t') {inbuf++; len++;} i=0; while ((c = *inbuf++) != NULL && c != ' ' && c != '\t' && c != '\n' && c != '$' && c != '}' && c != '~' && i < MAXWORD) {ww[i++] = (char)c; len++;} ww[i] = NULL; if (strcmp(ww,"roman") == 0 || strcmp(ww,"bold") == 0 || strcmp(w,"italic") == 0) { (void) get_arg(inbuf,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(inbuf,w,tab) char *inbuf, *w; int tab; { int c, i=0; for (i=0; (c = *inbuf++) != NULL && c != tab && i < MAXWORD; i++) w[i] = (char)c; w[i] = NULL; return(i); } int get_till_space(inbuf,w) /* get characters till the next space */ char *inbuf, *w; { int c,i; for (i=0; (c = *inbuf++) != NULL && c != ' ' && c != '\n' && c != '\t' && i < MAXWORD; i++) w[i] = (char)c; w[i] = NULL; return(i); } int getdef(inbuf,ww) /* get the define substitution */ char *inbuf, *ww; { int c,i,len; int def_delim; char w[MAXWORD]; def_delim = *inbuf++; /* take first character as delimiter */ len=1; i=0; while ((c = *inbuf++) != NULL && c != def_delim && i < MAXWORD) {len++; w[i++] = (char)c;} w[i] = NULL; 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); } int getword(inbuf,w) /* get an alphanumeric word (dot also) */ char *inbuf, *w; { int c,i; for (i=0; (c = *inbuf++) != NULL && (isalpha(c) || isdigit(c) || c == '.') && i < MAXWORD; i++) w[i] = (char)c; if (i == 0 && c != NULL) w[i++] = (char)c; w[i] = NULL; return(i); } void GR_to_Greek(w,ww) /* change GREEK to Greek */ char *w, *ww; { *ww++ = '\\'; *ww++ = *w; while(*++w != NULL) *ww++ = tolower(*w); *ww = NULL; } int is_def(w) /* check if w was defined by the user */ char *w; { int i; for (i=0; i < def_count; i++) { if (strcmp(def[i].def_macro,w) == 0) return(i); } return(-1); } int is_flip(w) /* check if w is in the flip list */ char *w; { int i; for (i=0; i < flip_count; i++) { if (strcmp(flip_list[i],w) == 0) return(i); } return(-1); } int is_forbid(w) /* check if w is one of those sacred macros */ char *w; { int i; for (i=0; i < forbd_count; i++) { if (strcmp(forbid[i],w) == 0) return(i); } return(-1); } int is_mathcom(w,ww) /* check if w has a simple correspondence in TeX */ char *w,*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_mydef(w) /* check if w is user-defined macro */ char *w; { int i; for (i=0; i < mydef_count; i++) { if (strcmp(mydef[i].def_macro,w) == 0) return(i); } return(-1); } int is_troff_mac(w,ww,arg,par)/* check if w is a macro or plain troff command */ char *w,*ww; int *arg,*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(ww,sign,value,units) char *ww; int *sign, *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] = NULL; 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); } } void scrbuf(in,out) /* copy input to output */ FILE *in,*out; { int c; while ((c =getc(in)) != EOF) putc(c,out); } int similar(w) /* check if w is in the similar list */ char *w; { int i; for (i=0; i < sim_count ; i++) { if (strcmp(sim_list[i],w) == 0) return(1); } return(-1); } char * skip_line(inbuf) /* ignore the rest of the line */ char *inbuf; { while (*inbuf != '\n' && *inbuf != NULL) inbuf++; if (*inbuf == NULL) return(inbuf); else return(++inbuf); } int skip_white(inbuf) /* skip white space */ char *inbuf; { int c,len=0; while ((c = *inbuf++) == ' ' || c == '\t' || c == '\n') len++; return(len); } char * strapp(s,tail) /* copy tail[] to s[], return ptr to terminal NULL in s[] */ register char *s; /* Nelson Beebe */ register char *tail; { while (*s++ = *tail++) /*NO-OP*/; return (s-1); /* pointer to NULL at end of s[] */ } void tmpbuf(in,buffer) /* copy input to buffer, buffer holds only MAXLEN characters */ 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 = NULL; } SHAR_EOF fi # end of overwriting check if test -f 'setups.h' then echo shar: will not over-write existing file "'setups.h'" else cat << \SHAR_EOF > 'setups.h' /* setup file */ #ifndef NO_SGTTY #define HAVE_SGTTY 1 /* host has sgtty.h and ioctl.h */ #endif #include <stdio.h> #include <ctype.h> #ifdef MSC #include <string.h> #include <stdlib.h> /* for type declarations */ #include <io.h> /* for type declarations */ #else #include <strings.h> #endif #if HAVE_SGTTY #include <sys/ioctl.h> #include <sgtty.h> #endif #define MAXLEN 65535 /* maximum length of document */ #define MAXWORD 250 /* maximum word length */ #define MAXLINE 500 /* maximum line length */ #define MAXDEF 200 /* maximum number of defines */ extern char *malloc(); #ifdef IN_TR /* can only declare globals once */ #else extern #endif int math_mode, /* math mode status */ de_arg, /* .de argument */ IP_stat, /* IP status */ QP_stat, /* QP status */ TP_stat; /* TP status */ #ifdef IN_TR /* can only declare globals once */ #else extern #endif struct defs { char *def_macro; char *replace; int illegal; } def[MAXDEF]; #ifdef IN_TR /* can only declare globals once */ #else extern #endif struct mydefs { char *def_macro; char *replace; int illegal; int arg_no; int par; /* if it impiles (or contains) a par break */ } mydef[MAXDEF]; #ifdef IN_TR /* can only declare globals once */ #else extern #endif struct measure { char old_units[MAXWORD]; float old_value; char units[MAXWORD]; float value; char def_units[MAXWORD]; /* default units */ int def_value; /* default value: 0 means take last one */ } linespacing, indent, tmpind, space, vspace; #ifdef ANSI char* alternate(char*, char*, char*); int CAP_GREEK(char*); char* do_table(char*,char*,int); char* end_env(char*); void envoke_stat(int); char* flip(char*,char*); char* flip_twice(char*,char*,char*); int get_arg(char*,char*,int ,int ); void get_brace_arg(char*,char*); int get_defword(char*,char*,int*); int get_line(char*,char*,int ); int get_multi_line(char*,char*); int get_mydef(char*,char*); int get_N_lines(char *,char *,int); int get_no_math(char*,char*); char* get_over_arg(char*,char*); int get_ref(char*,char*); int get_string(char*,char*,int ); void get_size(char*,char*,char*); int get_sub_arg(char*,char*); int get_till_space(char*,char*); int getdef(char*,char*); int getword(char*,char*); void GR_to_Greek(char*,char*); int is_def(char*); int is_flip(char*); int is_forbid(char*); int is_mathcom(char*,char*); int is_mydef(char *); int is_troff_mac(char*,char*,int*); int main(int ,char **); void parse_units(char*,int,int,int); void scrbuf(FILE*,FILE*); int similar(char*); char* skip_line(char*); int skip_white(char*); char* strapp(char*,char*); void tmpbuf(FILE*,char*); void troff_tex(char *,char *,int ); #else char* alternate(); int CAP_GREEK(); char* do_table(); char* end_env(); void envoke_stat(); char* flip(); char* flip_twice(); int get_arg(); void get_brace_arg(); int get_defword(); int get_line(); int get_multi_line(); int get_mydef(); int get_N_lines(); int get_no_math(); char* get_over_arg(); int get_ref(); int get_string(); void get_size(); int get_till_space(); int get_sub_arg(); int getdef(); int getword(); void GR_to_Greek(); int is_def(); int is_flip(); int is_forbid(); int is_mathcom(); int is_mydef(); int is_troff_mac(); int main(); void parse_units(); void scrbuf(); int similar(); char* skip_line(); int skip_white(); char* strapp(); void tmpbuf(); void troff_tex(); #endif SHAR_EOF fi # end of overwriting check if test -f 'simil.h' then echo shar: will not over-write existing file "'simil.h'" else cat << \SHAR_EOF > 'simil.h' /* This file contains a list of math words that are similar in the two languages (in fact identical except for TeX's backslah). If I overlooked anything out, it can be put here Do NOT put here words that are similar but require some action (like over) */ char *sim_list[] = { "alpha", "approx", "beta", "cdot", "chi", "cos", "cosh", "cot", "coth", "delta", "epsilon", "eta", "exp", "gamma", "int", "kappa", "lambda", "lim", "log", "matrix", "mu", "nu", "omega", "partial", "phi", "pi", "prime", "prod", "psi", "rho", "sigma", "sin", "sinh", "sqrt", "sum", "tan", "tanh", "tau", "theta", "times", "xi", "zeta" }; SHAR_EOF fi # end of overwriting check if test -f 'greek.h' then echo shar: will not over-write existing file "'greek.h'" else cat << \SHAR_EOF > 'greek.h' /* This file contains the list of the upper-case Greek letters. In case I overlooked any, it can be added here. */ char *GRK_list[] = { "ALPHA", "BETA", "CHI", "DELTA", "EPSILON", "ETA", "GAMMA", "KAPPA", "LAMDA", "MU", "NU", "OMEGA", "PHI", "PI", "PSI", "RHO", "SIGMA", "TAU", "THETA", "XI", "ZETA" }; SHAR_EOF fi # end of overwriting check if test -f 'flip.h' then echo shar: will not over-write existing file "'flip.h'" else cat << \SHAR_EOF > 'flip.h' /* This file contains the words that are placed the opposite way in troff and TeX. Is there any more? */ char *flip_list[] = { "bar", "dot", "dotdot", "hat", "tilde", "under", "vec" }; SHAR_EOF fi # end of overwriting check if test -f 'forbid.h' then echo shar: will not over-write existing file "'forbid.h'" else cat << \SHAR_EOF > 'forbid.h' /* This file contains TeX commands that cannot be re-defined. Re-defining them is not permitted by TeX (or they may produce unpredictable consequences). If the troff user happens to re-define one of these, it will be replaced. This list is extracted from the starred entries in the index of the TeXBook. They are entered here in alphabetical order. If the macro has non-alphabetical characters, it will be trapped somewhere else; it needn't be put here. This list is added to make the program more robust. Note that the backslash is omitted. */ char *forbid[] = { "atop", "char", "copy", "count", "cr", "crcr", "day", "def", "divide", "dp", "dump", "edef", "else", "end", "eqno", "fam", "fi", "font", "gdef", "global", "halign", "hbox", "hfil", "hfill", "hfuzz", "hoffset", "hrule", "hsize", "hskip", "hss", "ht", "if", "ifcase", "ifcat", "ifnum", "ifodd", "iftrue", "ifx", "indent", "input", "insert", "kern", "left", "leqno", "let", "limits", "long", "lower", "mag", "mark", "mkern", "month", "mskip", "multiply", "muskip", "omit", "or", "outer", "output", "over", "overline", "par", "raise", "read", "right", "show", "span", "special", "string", "the", "time", "toks", "topmark", "topskip", "unkern", "unskip", "vbox", "vfil", "vfill", "vfuzz", "voffset", "vrule", "vsize", "vskip", "vsplit", "vss", "vtop", "wd", "write", "xdef" }; SHAR_EOF fi # end of overwriting check if test -f 'macros.h' then echo shar: will not over-write existing file "'macros.h'" else cat << \SHAR_EOF > 'macros.h' /* This file contains the list of non-math macros and plain troff macros. Do NOT forget to put the dot for the troff macros, and the backslash for TeX macros (two backslashes, one for escape). The third column in the list is 0 for macros that have no arguments and either 1 or 2 for those that do. If it is 1, then only one line will be read as an argument. If it is 2, then lines will be read until properly terminated. Arguments for ms macros are terminated by an ms macro (e.g. .PP). Plain troff macros are terminated after reading the desired number of lines specified by the macro (e.g. .ce 5 will centerline 5 lines). The fourth column specifies whether the macro implies a paragraph break (par > 1) or not (par = 0). This is needed to terminate some environments. If .LP, or .PP, par=1; if .IP, par=2; if .TP, par=3; if .QP, par=4. */ struct macro_table { char *troff_mac, *tex_mac; int arg, macpar; } macro[] = { /* troff macro TeX macro argument par */ ".1C", "\\onecolumn", 0, 1, ".2C", "\\twocolumn", 0, 1, ".AE", "\\end{abstract}", 0, 1, ".AI", "\\authoraff", 2, 1, ".AU", "\\author", 2, 1, ".Ac", "\\ACK", 0, 1, ".B1", "\\boxit{", 0, 0, ".B2", "}", 0, 0, ".DE", "\\displayend", 0, 1, ".DS", "\\displaybegin", 0, 1, ".FE", "}", 0, 0, ".FS", "\\footnote{", 0, 0, ".Ic", "\\caption{", 0, 1, ".Ie", "}\\end{figure}", 0, 1, ".Is", "\\begin{figure}", 0, 1, ".KS", "{\\nobreak", 0, 0, ".LP", "\\par\\noindent", 0, 1, ".MH", "\\mhead", 2, 1, ".NH", "\\section", 1, 1, ".PP", "\\par", 0, 1, ".QE", "\\end{quotation}", 0, 1, ".QS", "\\begin{quotation}", 0, 1, ".SH", "\\shead", 1, 1, ".TH", "\\phead", 1, 0, ".TL", "\\title", 2, 1, ".UC", "", 0, 0, ".UL", "\\undertext", 1, 0, ".bp", "\\newpage", 0, 1, ".br", "\\nwl", 0, 0, ".ce", "\\cntr", 2, 0, ".cu", "\\undertext", 2, 0, ".fi", "\\fill", 0, 0, ".na", "\\raggedright", 0, 0, ".nf", "\\nofill", 0, 0, ".ns", "", 0, 0, ".ul", "\\undertext", 2, 0 }; SHAR_EOF fi # end of overwriting check if test -f 'maths.h' then echo shar: will not over-write existing file "'maths.h'" else cat << \SHAR_EOF > 'maths.h' /* This file contains a list of the words that have simple correspondence in the two languages. Do not put here words that require action (like sub). If the word is identical in the two languages (except for TeX's backslash), put it in simil.h */ struct math_equiv { char *troff_symb, *tex_symb; } math[] = { /* troff name TeX name */ "~", "\\ ", "^", "\\,", "above", "\\cr", "ccol", "\\matrix", "cpile", "\\matrix", "fat", "", "grad", "\\nabla", "half", "{1\\over 2}", "inf", "\\infty", "inter", "\\cap", "lcol", "\\matrix", "lineup", "", "lpile", "\\matrix", "mark", "", "nothing", "", "pile", "\\matrix", "rcol", "\\matrix", "rpile", "\\matrix", "union", "\\cup" }; SHAR_EOF fi # end of overwriting check if test -f 'makefile' then echo shar: will not over-write existing file "'makefile'" else cat << \SHAR_EOF > 'makefile' # Use makefile.msc if you are compiling with MS-DOS # add -Dtops20 to CFLAGS if you're running it under tops20 # and add -DANSI if you're using ANSI C CFLAGS = LINTFLAGS = -abchnpux CFILES = tr2tex.c tr.c subs.c HFILES = setups.h simil.h greek.h macros.h maths.h flip.h forbid.h B = default: tr2tex tr2tex: tr2tex.o tr.o subs.o cc $(CFLAGS) tr2tex.o tr.o subs.o -o $(B)tr2tex tr2tex.o: tr2tex.c setups.h cc $(CFLAGS) -c tr2tex.c tr.o: tr.c setups.h cc $(CFLAGS) -c tr.c subs.o: subs.c $(HFILES) cc $(CFLAGS) -c subs.c lint: lint $(LINTFLAGS) $(CFILES) > lint.lst clean: \rm -f *.o core *junk* tr2tex lint.lst SHAR_EOF fi # end of overwriting check if test -f 'makefile.msc' then echo shar: will not over-write existing file "'makefile.msc'" else cat << \SHAR_EOF > 'makefile.msc' #----------------------------------------------------------------------- # Makefile for troff-to-TeX translator using MS-DOS # Make targets: # (none) same as tr2tex # tr2tex build translator # lint run lint on sources # clean remove object and executable files # share make ../ttr.sh for mailing # # Author: Nelson H.F. Beebe 25-Oct-86 CFLAGS = -O -DMSC -DNO_SGTTY CFILES = tr2tex.c tr.c subs.c LINTFLAGS = -abchnpux B = tr2tex: tr2tex.o tr.o subs.o cc $(CFLAGS) tr2tex.o tr.o subs.o -o $(B)tr2tex share: make clean makescript ../ttr.sh * tr2tex.o: tr2tex.c setups.h cc $(CFLAGS) -c tr2tex.c tr.o: tr.c setups.h cc $(CFLAGS) -c tr.c subs.o: subs.c setups.h similar.h greek.h flip.h troff_mac.h mathcom.h cc $(CFLAGS) -c subs.c lint: lint $(LINTFLAGS) $(CFILES) > lint.lst clean: \rm -f *.o core *junk* tr2tex lint.lst SHAR_EOF fi # end of overwriting check if test -f 'troffms.sty' then echo shar: will not over-write existing file "'troffms.sty'" else cat << \SHAR_EOF > 'troffms.sty' % You need these macros since they are refered to by the translator. % You can modify them if you want. % I would very much want better macros for the headers and footers. % Please pass your suggestions to me. -Kamal \def\ps@sepone{% \def\@oddhead{} \def\@evenhead{} \def\@oddfoot{\hfil\it\sepfoot\hfil} \def\@evenfoot{\hfil\it\sepfoot\hfil}} \def\ps@sep{% \def\@oddhead{\hbox{}\it\seprhead\hfil\it\seplhead} \def\@evenhead{\it\seprhead\hfil\it\seplhead\hbox{}} \def\@oddfoot{\hfil\it\sepfoot\hfil} \def\@evenfoot{\hfil\it\sepfoot\hfil}} \pagestyle{sep} \def\righthead#1{\def\seplhead{#1}} \def\lefthead#1{\def\seprhead{#1}} \def\footer#1{\def\sepfoot{#1}} \footer{} \lefthead{} \righthead{} \thispagestyle{sepone} \def\makefootline{\baselineskip24\p@\line{\the\footline}} \def\makeheadline{\vbox to 0pt{\vskip-22.5pt \line{vbox to 8.5pt{}\the\headline}\vss}\nointerlineskip} \newfont{\bigbf}{ambx10 scaled\magstep 3} \newfont{\bigit}{amti10 scaled\magstep 2} \newfont{\bigrm}{amr10 scaled\magstep 2} \textheight=9in \textwidth=6.4in \textfloatsep 30pt plus 3pt minus 6pt \parskip=5pt \oddsidemargin=-.2in \voffset=-.1in \newdimen\singlespacing \singlespacing=11pt % single line spacing \normalbaselineskip=15pt % 1.5 line spacing \baselineskip=\normalbaselineskip % multi-line title \newenvironment{SEPtitle}{\begin{center}\bigbf}{\end{center}} \def\title#1{ \begin{SEPtitle} \vbox{\baselineskip=1.5\normalbaselineskip \vskip1in #1\vskip.3in} \end{SEPtitle}} % multi-line author \newenvironment{SEPauthor}{\begin{center}\bigit}{\end{center}} \def\author#1{ \begin{SEPauthor} \vbox{#1 \vskip.3cm} \end{SEPauthor}} \newenvironment{SEPauthoraff}{\begin{center}\bigrm}{\end{center}} \def\authoraff#1{ \begin{SEPauthoraff} \vbox{#1 \vskip.2in} \end{SEPauthoraff}} % multi-line centered section heading \newenvironment{SEPmhead}{\begin{center}\bf}{\end{center}} \def\mhead#1{\pagebreak[3] \begin{SEPmhead}\pagebreak[3] \vbox{\vskip.3in #1}\nopagebreak \end{SEPmhead}\nopagebreak} % multi-line left-justified subheading \newenvironment{SEPshead}{\begin{flushleft}\bf}{\end{flushleft}} \def\shead#1{\pagebreak[3] \begin{SEPshead}\pagebreak[3] \vbox{\vskip.2in #1}\nopagebreak \end{SEPshead}\nopagebreak} % define ABSTRACT, INTRODUCTION, DISCUSSION, CONCLUSIONS, REFERENCES, % and APPENDIX as the first three letters \def\ABS{\mhead{ABSTRACT}} \def\INT{\mhead{INTRODUCTION}} \def\DIS{\mhead{DISCUSSION}} \def\CON{\mhead{CONCLUSIONS}} \def\ACK{\mhead{ACKNOWLEDGMENT}} \def\REF{\mhead{REFERENCES}} \def\APP{\mhead{APPENDIX}} % reference macro, second ... lines are indented \newdimen\dtmp % temporary dimension variable \def\reference#1{ \baselineskip=\singlespacing \dtmp=\hsize \advance\dtmp by-\parindent \parshape 2 0in \hsize \parindent \dtmp \noindent #1 \endgraf \baselineskip=\normalbaselineskip \vskip4pt } \newcommand{\bs}{$\backslash$} \def\under{\underline} \def\dotdot{\ddot} \def\nwl{\hfill\break} % similar to latex's \newline but does not % complain if there is no line to break \def\ind#1{\par\everypar{\hangindent=#1\hangafter=0\hskip-\parindent}} \def\tmpind#1{\par\hskip#1} \newenvironment{SEPcntr}{\begin{center}}{\end{center}} \def\cntr#1{\begin{SEPcntr} #1 \end{SEPcntr}} % displayed text, indented, justification off \def\displaybegin{\par\begingroup\medskip\narrower\narrower\noindent \obeylines\obeyspaces} \def\displayend{\endgroup\smallskip\noindent} % fill and nofill \def\nofill{\par\begingroup\noindent\obeylines \frenchspacing\@vobeyspaces\linepenalty10000} {\catcode`\ =\active\gdef\@vobeyspaces{\catcode`\ \active \let \@xobeysp}} \def\@xobeysp{\leavevmode{} } \def\fill{\endgroup\noindent} % define a boxing macro \def\boxit#1{\vbox{\hrule\hbox{\vrule\kern10pt\vbox{\medskip\kern5pt#1\bigskip \kern5pt}\kern10pt\vrule}\hrule}} SHAR_EOF fi # end of overwriting check if test -f 'troffman.sty' then echo shar: will not over-write existing file "'troffman.sty'" else cat << \SHAR_EOF > 'troffman.sty' % -*-LaTeX-*- % <BEEBE.TR2TEX>TROFFMAN.STY.6, 24-Feb-87 09:53:53, Edit by BEEBE % These macros are intended to be referenced by a LaTeX % \documentstyle[troffman]{article} % command. You can insert an 11pt or 12pt option if you like larger % type--sizes set here are computed from the LaTeX point size setting. % Size values have been chosen to closely match Unix manual page % documents, which are actually too wide and too high for good % typographic taste and readability. % \hbadness=10000 % do not want underfull box messages--there are % usually lots in man pages \hfuzz=\maxdimen % no overfull box messages either \voffset=-0.8in % man pages start high on page \textheight=9in % and are long \textwidth=6.5in % troff man pages have very wide text \parindent=0pt \oddsidemargin=-.2in \newdimen\singlespacing \singlespacing=10pt % LaTeX has (10+\@ptsize)pt \addtolength{\singlespacing}{\@ptsize pt} % get size from \documentstyle[??pt]{} % Use conventional typesetting baselineskip spacing for 10pt type \normalbaselineskip=1.2\singlespacing \newlength{\parmargin} % whole paragraphs indented this much on man pages \parmargin=3\normalbaselineskip \baselineskip=\normalbaselineskip % page heading/footing % NB: we need \hfill, not \hfil, here; otherwise box is filled only to current % paragraph width \newcommand{\phead}[3]{% \renewcommand{\@oddhead}{%\@setpar{\hangindent=0pt\hangafter=0\@@par} {\makebox[\textwidth]{#1(#2) \hfill \rm UNIX Programmer's Manual% \hfill #1(#2)}}}% \renewcommand{\@oddfoot}{%\@setpar{\hangindent=0pt\hangafter=0\@@par} {\makebox[\textwidth]{4th Berkeley distribution \hfill #3% \hfill \rm\thepage}}}% \renewcommand{\@evenfoot}{\@oddfoot}% \renewcommand{\@evenhead}{\@oddhead}% } % multi-line left-justified subheading \def\shead#1{ \par % force out previous paragraph with its \hangindent values \@setpar{\hangindent=0pt\hangafter=0\@@par} \typeout{[#1]} % maybe temporary, but nice for progress report \subsubsection*{#1} \@setpar{\hangindent=\parmargin\hangafter=0\@@par} } \newcommand{\bs}{$\backslash$} \def\under{\underline} \def\dotdot{\ddot} \def\nwl{\hfill\break} % similar to LaTex's \newline but does not % complain if there is no line to break \def\ind#1{\par\everypar{\hangindent=#1\hangafter=0\hskip-\parindent}} \def\tmpind#1{\par\hskip#1} \newenvironment{SEPcntr}{\begin{center}}{\end{center}} \def\cntr#1{\begin{SEPcntr} #1 \end{SEPcntr}} % displayed text, indented, justification off \def\displaybegin{\par\begingroup\medskip\narrower\narrower\noindent \obeylines\obeyspaces} \def\displayend{\endgroup\smallskip\noindent} % fill and nofill \def\nofill{\par\begingroup\noindent\obeylines \frenchspacing\@vobeyspaces\linepenalty10000} {\catcode`\ =\active\gdef\@vobeyspaces{\catcode`\ \active \let \@xobeysp}} \def\@xobeysp{\leavevmode{} } \def\fill{\endgroup\noindent} % define a boxing macro \def\boxit#1{\vbox{\hrule\hbox{\vrule\kern10pt\vbox{\medskip\kern5pt#1\bigskip \kern5pt}\kern10pt\vrule}\hrule}} % try this TPlist environment \newcommand{\TPlistlabel}[1]{\mbox{#1}\hfil} \newenvironment{TPlist}[1]{ \begin{list}{} { \let\makelabel\TPlistlabel \settowidth{\labelwidth}{#1mm} \setlength{\leftmargin}{\parmargin} % all paragraphs have this much \addtolength{\leftmargin}{\labelwidth} % space for label } }{ \end{list}} SHAR_EOF fi # end of overwriting check if test -f 'tr2tex.9' then echo shar: will not over-write existing file "'tr2tex.9'" else cat << \SHAR_EOF > 'tr2tex.9' .TH TR2TEX 9 "1 January 1987" .UC 4 .SH NAME tr2tex \- convert a document from troff to LaTeX .SH SYNOPSIS .B tr2tex [ .B -m ] .I filename .SH DESCRIPTION .B Tr2tex converts a document typeset in .B troff to a .B LaTeX format. It is intended to do the first pass of the conversion. The user should then finish up the rest of the conversion and customize the converted manuscript to his/her liking. It can also serve as a tutor for those who want to convert from troff to LaTeX. .PP Most of the converted document will be in LaTeX but some of it may be in plain .B TeX. It will also use some macros in .B troffms.sty or .B troffman.sty which are included in the package and must be available to the document when processed with LaTeX. .PP If there is more than one input file, they will all be converted into one LaTeX document. .PP .B Tr2tex understands most of the .B -ms and .B -man macros and .B eqn preprocessor symbols. It also understands several plain .B troff commands. Few .B tbl preprocessor commands are understood to help convert very simple tables. .PP When converting manuals, use the .B -m flag. .PP If a troff command cannot be converted, the line that contain that command will be commented out. .PP NOTE: if you have .B eqn symbols, you must have the in-line mathematics delimiter defined by .B delim in the file you are converting. If it is defined in another setup file, that setup file has to be concatenated with the file to be converted, otherwise .B tr2tex will regard the in-line math as ordinary text. .SH BUGS Many of these bugs are harmless. Most of them cause local errors that can be fixed in the converted manuscript. .PP \- Some macros and macro arguments are not recognized. .PP \- Commands that are not separated from their argument by a space are not properly parsed (e.g .sp3i). .PP \- When some operators (notably over, sub and sup) are renamed (via define), then they are encountered in the text, .B tr2tex will treat them as ordinary macros and will not apply their rules. .PP \- rpile, lpile and cpile are treated the same as cpile. .PP \- rcol, lcol are treated the same as ccol. .PP \- Math-mode size, gsize, fat, and gfont are ignored. .PP \- lineup and mark are ignored. The rules are so different. .PP \- Some troff commands are translated to commands that require delimiters that have to be explicitly put. Since they are sometimes not put in troff, they can create problems. Example: .nf not closed by .fi. .PP \- When local motions are converted to \\raise or \\lower, an \\hbox is needed, which has to be put manually after the conversion. .PP \- 'a sub i sub j' is converted to 'a_i_j' which TeX parses as 'a_i{}_j}' with a complaint that it is vague. 'a sub {i sub j}' is parsed correctly and converted to 'a_{i_j}'. .PP \- Line spacing is not changed within a paragraph in TeX (which is a bad practice anyway). TeX uses the last line spacing in effect in that paragraph. .SH TODO Access registers via .B .nr command. .SH SEE ALSO texmatch(9), trmatch(9). .SH AUTHOR Kamal Al-Yahya, Stanford University SHAR_EOF fi # end of overwriting check if test -f 'tr2tex.9-tex-orig' then echo shar: will not over-write existing file "'tr2tex.9-tex-orig'" else cat << \SHAR_EOF > 'tr2tex.9-tex-orig' % -*-LaTeX-*- % Converted automatically from troff to LaTeX by tr2tex on Fri Feb 20 12:05:23 1987 % tr2tex was written by Kamal Al-Yahya at Stanford University % (Kamal%Hanauma@SU-SCORE.ARPA) \documentstyle[troffman]{article} \begin{document} % % input file: tr2tex.9 % \phead{TR2TEX}{9}{1\ January\ 1987} \shead{NAME} tr2tex -- convert a document from troff to LaTeX \shead{SYNOPSIS} {\bf tr2tex} [ {\bf -m} ] {\it filename} \shead{DESCRIPTION} {\bf Tr2tex} converts a document typeset in {\bf troff} to a {\bf LaTeX} format. It is intended to do the first pass of the conversion. The user should then finish up the rest of the conversion and customize the converted manuscript to his/her liking. It can also serve as a tutor for those who want to convert from troff to LaTeX. \par Most of the converted document will be in LaTeX but some of it may be in plain {\bf TeX.} It will also use some macros in {\bf troffms.sty} or {\bf troffman.sty} which are included in the package and must be available to the document when processed with LaTeX. \par If there is more than one input file, they will all be converted into one LaTeX document. \par {\bf Tr2tex} understands most of the {\bf -ms} and {\bf -man} macros and {\bf eqn} preprocessor symbols. It also understands several plain {\bf troff} commands. Few {\bf tbl} preprocessor commands are understood to help convert very simple tables. \par When converting manuals, use the {\bf -m} flag. \par If a troff command cannot be converted, the line that contain that command will be commented out. \par NOTE: if you have {\bf eqn} symbols, you must have the in-line mathematics delimiter defined by {\bf delim} in the file you are converting. If it is defined in another setup file, that setup file has to be concatenated with the file to be converted, otherwise {\bf tr2tex} will regard the in-line math as ordinary text. \shead{BUGS} Many of these bugs are harmless. Most of them cause local errors that can be fixed in the converted manuscript. \par -- Some macros and macro arguments are not recognized. \par -- Commands that are not separated from their argument by a space are not properly parsed (e.g .sp3i). \par -- When some operators (notably over, sub and sup) are renamed (via define), then they are encountered in the text, {\bf tr2tex} will treat them as ordinary macros and will not apply their rules. \par -- rpile, lpile and cpile are treated the same as cpile. \par -- rcol, lcol are treated the same as ccol. \par -- Math-mode size, gsize, fat, and gfont are ignored. \par -- lineup and mark are ignored. The rules are so different. \par -- Some troff commands are translated to commands that require delimiters that have to be explicitly put. Since they are sometimes not put in troff, they can create problems. Example: .nf not closed by .fi. \par -- When local motions are converted to \bs raise or \bs lower, an \bs hbox is needed, which has to be put manually after the conversion. \par -- 'a sub i sub j' is converted to 'a\_i\_j' which TeX parses as 'a\_i\{\}\_j\}' with a complaint that it is vague. 'a sub \{i sub j\}' is parsed correctly and converted to 'a\_\{i\_j\}'. \par -- Line spacing is not changed within a paragraph in TeX (which is a bad practice anyway). TeX uses the last line spacing in effect in that paragraph. \shead{TODO} Access registers via {\bf .nr} command. \shead{SEE ALSO} texmatch(9), trmatch(9). \shead{AUTHOR} Kamal Al-Yahya, Stanford University \end{document} SHAR_EOF fi # end of overwriting check if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' Please read this file before you install the program. Troff-to-TeX translator version .93, March 4, 1987. Copyright (C) by 1987 Kamal Al-Yahya. This directory contains programs that were developed at the Stanford Exploration Project, Geophysics Department, by Kamal Al-Yahya. Copying them to any other machine is permitted without prior permission provided that copyright messages are kept, no profit is made by copying the files, and modifications are clearly documented. I would very much appreciate any comments or suggestions. My e-net address is kamal@hanauma.stanford.edu If it doesn't work try kamal%hanauma@score.stanford.edu INSTALLATION INSTRUCTIONS In short, type ``make'' and then run it on the document (try the testfile): tr2tex testfile > testfile.tex In details: - Use makefile.msc if you're running MS-DOS. - In the makefile, define the destination of the executable (default is current directory). Also, add the -O flag if you want to (and the optimizer in your machine is not buggy). The -O flag causes long compilation time but experience has shown that it is unnecessary for this package; time saved in running time is extremely small in the computers I used. - If the limit on your unsigned int is not 65535, change MAXLEN in setups.h accordingly. - In tr2tex.c, change the document type if you want. The default is article. Also, change the style options to suit your taste. The default is [troffms,11pt] if no flag is used and [troffman] if the -m flag is used. - Add necessary -D's to CFLAGS if you need them. The program recognizes the following compiler-time definitions: -Dtops20, -DANSI, -DMSC, -DNO_SGTTY - type ``make'' to produce the executable, called ``tr2tex''. - Modify troffms.sty and troffman.sty to suit your taste but keep the necessary macro definitions as they will be needed when running latex. Make sure the font names exist on your site. Change them if necessary. - Move troffms.sty and troffman.sty to your macros directory. - Install and read the manual page. - Run the translator on ``testfile'' and the manual page as follows tr2tex testfile > testfile.tex tr2tex -m tr2tex.9 > tr2tex.9.tex and compare ``testfile.tex'' with ``testfile.tex-orig'' and ``tr2tex.9.tex'' with ``tr2tex.9-tex-orig''. If they are not identical, you have not installed it properly. USING THE TRANSLATOR You can run the program either by tr2tex < file > file.tex or tr2tex file > file.tex You are most likely to get messages on the standard error telling you about things it encounters and cannot do. Now you have the translated document. Look at it and see if you can spot a major error. Run it through latex. If it runs and produces the dvi file, then print it. If you get latex error messages modify the translated document accordingly and repeat the latex run, and so on. I usually get away with one or two iterations. SHAR_EOF fi # end of overwriting check if test -f 'testfile' then echo shar: will not over-write existing file "'testfile'" else cat << \SHAR_EOF > 'testfile' .LP .EQ delim $$ gsize 11 define dC "delta C" define xx 'x sup x' define B 'bold B' define (( 'left (' define )) 'right )' define ov 'over' .EN .ds CF % .ds LH Al-Yahya .ds RH troff to TeX translator .TL Testing the troff-to-tex translator .AU Kamal Al-Yahya .AI Stanford University .AB This file demonstrates the use of \fB tr2tex\fR which translates documents written in troff to a LaTeX style. Examples are given to show what the translator can do. .AE .PP First let's test some equation written for the .B eqn preprocessor: .EQ (1) 2 left ( 1 ~+~ sqrt{omega sub i+1 + zeta -{x+1} over {THETA +1} y + 1} right ) ~~~=~~~ 1 .EN .EQ left [ matrix { ccol { e sub 1 above . above . above e sub i above . above . above e sub N } } right ] sub n+1 ~~=~~ y + 1 .EN .EQ bold X + roman a ~>=~ a under hat fwd 20 sum from i to N lim from {x -> k} dC .EN .EQ (( "speed" times "time" = "distance travelled" )) .EN .EQ beta tilde i >= zeta dC .EN .IP In-line math like $beta +1$ which is surrounded by math delimiters, as defined by .I delim is also translated. .R .PP Only simple tables are translated. Translation of more complicated tables is painful and I won't do it now. Here is an example: .TS tab(&); l rc n. name & type & color & value $alpha$ & real & red & 2.3 $x$ & imaginary & green & -1.2 $a + 2$ & real & white & 0.0 .TE \" this is a commented text .PP Now we start a figure. .Is .sp 3i .Ic 1 This is the caption of the figure. .Ie .PP Try some floating objects. .br .KS This text should be kept in one page. i.e. a page break is discouraged here. .KE .br Now a floating text. .KF This text should be kept in one page even if we had to move it around, since it is a .I floating object. This is a boxed .BX word. .KE .br These characters are special in TeX, so they need to be escaped in the translation % & # _, while these characters have to be printed in math mode < > |. .FS This is a footnote .FE .PP .Ac Thanks to all of those who contributed by reporting bugs and suggesting some improvements. Special thanks go to Nelson Beebe for all of his valuable contributions and suggestions. He is responsible for making the translator portable to other computers. He also made significant improvements to the translation of manuals. .Re Knuth, D.E., 1984, The TeXBook, Addison-Wesley Publishing Company. .Re Lamprt, L., 1986, LaTeX: user's guide & reference manual, Addison-Wesley Publishing Company. .Re Lesk, M.E., 1978, Typing documents on the UNIX system: using the -ms macros with troff and nroff, UNIX programmer's manual, v. 2B, sec. 3. .Re McGilton, H. and Morgan, R., 1983, Introducing the UNIX system, McGraw-Hill Book Company. SHAR_EOF fi # end of overwriting check if test -f 'testfile.tex-orig' then echo shar: will not over-write existing file "'testfile.tex-orig'" else cat << \SHAR_EOF > 'testfile.tex-orig' % -*-LaTeX-*- % Converted automatically from troff to LaTeX by tr2tex on Tue Mar 3 23:25:31 1987 % tr2tex was written by Kamal Al-Yahya at Stanford University % (Kamal%Hanauma@SU-SCORE.ARPA) \documentstyle[troffms,11pt]{article} \begin{document} % % input file: testfile % \par\noindent \def\dC{\delta C} \def\xx{x^x} \def\B{{\bf B}} \def\ov{\over } \footer{\rm\thepage} \lefthead{Al-Yahya} \righthead{troff to TeX translator} \title{Testing the troff-to-tex translator} \author{Kamal Al-Yahya} \authoraff{Stanford University} \begin{abstract} This file demonstrates the use of % \bf tr2tex % \rm which translates documents written in troff to a LaTeX style. Examples are given to show what the translator can do. \end{abstract} \par First let's test some equation written for the {\bf eqn} preprocessor: $$ 2 \left( 1 \ +\ \sqrt{\omega_{i+1} + \zeta -{x+1 \over \Theta +1} y + 1} \right) \ \ \ =\ \ \ 1 \eqno (1)$$ $$ \left[ \matrix { \matrix { e_1 \cr . \cr . \cr e_i \cr . \cr . \cr e_N } } \right]_{n+1} \ \ =\ \ y + 1 $$ $$ {\bf X} + {\rm a} \ \ge\ \under{\hat a} \kern0.20em \sum_i^N \lim_{{x} \to k} \dC $$ $$ \left( \ \it\hbox{speed} \times \ \it\hbox{time} = \ \it\hbox{distance travelled} \right) $$ $$ \tilde \beta i \ge \zeta \dC $$ \begin{itemize} \item[{}] In-line math like $\beta +1$ which is surrounded by math delimiters, as defined by {\it delim} is also translated. \rm \end{itemize}\par Only simple tables are translated. Translation of more complicated tables is painful and I won't do it now. Here is an example: \par \begin{tabular}{lrcc} name & type & color & value\\ $\alpha$ & real & red & 2.3\\ $x$ & imaginary & green & -1.2\\ $a + 2$ & real & white & 0.0 \end{tabular} \par % this is a commented text \par Now we start a figure. \begin{figure} \par\vspace{3.0in} \caption{ This is the caption of the figure. }\end{figure} \par Try some floating objects. \nwl {\nobreak This text should be kept in one page. i.e. a page break is discouraged here. } \nwl Now a floating text. \begin{figure} This text should be kept in one page even if we had to move it around, since it is a {\it floating} object. This is a boxed \fbox{word.} \end{figure} \nwl These characters are special in TeX, so they need to be escaped in the translation \% \& \# \_, while these characters have to be printed in math mode $<$ $>$ $|$. \footnote{ This is a footnote } \par \ACK Thanks to all of those who contributed by reporting bugs and suggesting some improvements. Special thanks go to Nelson Beebe for all of his valuable contributions and suggestions. He is responsible for making the translator portable to other computers. He also made significant improvements to the translation of manuals. \REF \reference{Knuth, D.E., 1984, The TeXBook, Addison-Wesley Publishing Company.} \reference{Lamprt, L., 1986, LaTeX: user's guide \& reference manual, Addison-Wesley Publishing Company.} \reference{Lesk, M.E., 1978, Typing documents on the UNIX system: using the -ms macros with troff and nroff, UNIX programmer's manual, v. 2B, sec. 3.} \reference{McGilton, H. and Morgan, R., 1983, Introducing the UNIX system, McGraw-Hill Book Company.} \end{document} SHAR_EOF fi # end of overwriting check if test -f 'diffs.tex' then echo shar: will not over-write existing file "'diffs.tex'" else cat << \SHAR_EOF > 'diffs.tex' \documentstyle[tr2tex,11pt]{article} \begin{document} \def\troff{{\it troff}} \def\Troff{{\it Troff}} \def\ditroff{{\it ditroff}} \def\Ditroff{{\it Ditroff}} \title{Differences between \TeX\ and troff typesetters} Outlined below are the differences between \TeX\ and \troff\/ that I know from experience with the two languages most of which obtained while writing {\bf tr2tex}. Most of them are advantages \TeX\ has over \troff. There are actually more than one type of \TeX, the most used ones are \LaTeX and plain \TeX\ \Troff\/ can also be loaded with various macro packages to produce variations to plain \troff. Also, \ditroff\/ (device independent \troff) is becoming more and more the standard of \troff. The following comparison is made mainly between \LaTeX\ and {\bf ms} \troff. It will be mentioned if in a particular case \ditroff\/ makes a difference. \begin{itemize} \item \TeX\ is not system-dependent. \Troff\/ is a Unix tool. \item In \Troff, tables and equations are handled by preprocessors while in \TeX\ they are simultaneously processed with text. \item \Troff\/'s commands have to start at the beginning of the line and start with a dot. Equation symbols are recognized when delimited by space. All \TeX\ commands, in math or non-math mode, start with a backslash and they don't have to be placed at the beginning of the line. \item \TeX\ and \LaTeX\ commands are more verbose than \troff\/'s. This can be an advantage or disadvantage depending on the user. \item \TeX\ processes {\it boxes} such as lines and paragraphs as one unit. This means it can distribute {\it badness} over that box. For example, when a spacing between two lines needs to be large, because a line has large symbols, it will slightly stretch the line spacing in other lines to make the large spacing not look too bad. This also makes it avoid orphan lines. \item The input to \LaTeX\ is a more structured document with scopes. It makes it easier to proofread. \Troff\/'s input is less structured. \item Some \TeX\ drivers make it very easy to include prepared graphs with the text. Including graphs with \troff\/'s text is more difficult. \item Many fonts can be loaded in a \TeX\ document (up to 32); in \troff, the limit is 4 (\ditroff\/ does not have this restriction). \item Non-math macros are defined just like math macros in \TeX. In \troff, {\bf define} is used for math definitions and {\bf .de} is used for non-math macros. \Troff\/'s macros can be made up from anything while \TeX\ macros cannot have non-letters which is a nuisance sometimes. \item There is no limit on the page size in \TeX. The size is limited only by the output device. \Troff\/'s paper size is limited. \item \TeX\ is interactive, while \troff\/ is not. However, not many people can benefit from this feature since they have to be skillful in answering its questions. \item \TeX\ and \LaTeX\ give a {\bf l\,o\,n\,g} ambiguous log file that does not exactly tell what the error is. \Troff\/ does not give error messages. \item \LaTeX\ automatically numbers equations and figures, etc. A powerful cross-referencing technique relieves the user from worrying about having the right sequence of equations' and figures' numbers. This feature is not available in \troff. \item The documentation in the \LaTeX\ manual is excellent. \Troff\/'s documentation is scattered over many references. The documentation in the \TeX Book is very technical and the average reader may find it unreadable. \item At hanauma, we have a previewer for TeX on the SUN, but don't have it for \troff. \end{itemize} \end{document} SHAR_EOF fi # end of overwriting check # End of shell archive exit 0