/* $Id: mpto.c,v 1.15 2005/08/28 11:42:55 taco Exp $ * Public domain. * * Previous versions of mpto were copyright 1990 - 1995 by AT&T Bell * Laboratories. It has since been put into the public domain. * * John Hobby wrote the original version, which has since been * extensively altered. */ /* mpto [-tex|-troff] MPFILE * * This program transforms a MetaPost input file into a TeX or troff input * file by stripping out btex...etex and verbatimtex...etex sections. * Leading and trailing spaces and tabs are removed from the extracted * material and it is surrounded by the preceding and following strings * defined immediately below. The input file should be given as argument 1 * and the resulting TeX or troff file is written on standard output. * * Changes incorporated from Web2c: * - merged TeX and troff mode * - support -E, for AMIGA */ #include #include #ifdef WIN32 #include #endif /* MetaPost itself has a configurable max line length, but we can afford to use smaller values than that */ #define bufsize 1000 char* tex_predoc = ""; char* tex_postdoc = "\\end{document}\n"; char* tex_pretex1 = "\\gdef\\mpxshipout{\\shipout\\hbox\\bgroup%\n" " \\setbox0=\\hbox\\bgroup}%\n" "\\gdef\\stopmpxshipout{\\egroup" " \\dimen0=\\ht0 \\advance\\dimen0\\dp0\n" " \\dimen1=\\ht0 \\dimen2=\\dp0\n" " \\setbox0=\\hbox\\bgroup\n" " \\box0\n" " \\ifnum\\dimen0>0 \\vrule width1sp height\\dimen1 depth\\dimen2 \n" " \\else \\vrule width1sp height1sp depth0sp\\relax\n" " \\fi\\egroup\n" " \\ht0=0pt \\dp0=0pt \\box0 \\egroup}\n" "\\mpxshipout%% line %d %s\n"; char* tex_pretex = "\\mpxshipout%% line %d %s\n"; char* tex_posttex = "\\stopmpxshipout\n"; char* tex_preverb1 = ""; /* if very first instance */ char* tex_preverb = "%% line %d %s\n"; /* all other instances */ char* tex_postverb = "%\n"; /* According to CSTR #54 the ".lf" directive should be ".lf %d %s", * not ".lf line %d %s" as used in the original code. This affects * troff_pretex1, troff_pretex, troff_preverb1, troff_preverb. */ char* troff_predoc = ".po 0\n"; char* troff_postdoc = ""; char* troff_pretex1 = ".lf %d %s\n"; /* first instance */ char* troff_pretex = ".bp\n.lf %d %s\n"; /* subsequent instances */ char* troff_posttex = "\n"; char* troff_preverb1 = ".lf %d %s\n"; char* troff_preverb = ".lf %d %s\n"; char* troff_postverb = "\n"; char* predoc; char* postdoc; char* pretex1; char* pretex; char* posttex; char* preverb1; char* preverb; char* postverb; char *mpname; FILE *mpfile; int lnno = 0; /* current line number */ int texcnt = 0; /* btex..etex blocks so far */ int verbcnt = 0; /* verbatimtex..etex blocks so far */ char *bb, *tt, *aa; /* start of before, token, and after strings */ char buf[bufsize]; /* the input line */ void err (char * msg) { fprintf(stderr, "mpto: %s:%d: %s\n",mpname, lnno, msg); exit(1); } void usage (char *progn) { fprintf(stderr, "Try `%s --help' for more information\n", progn); exit(1); } char * getline(void) /* returns NULL on EOF or error, otherwise buf */ { int c; unsigned loc = 0; while ((c = getc (mpfile)) != EOF && c != '\n' && c != '\r') { buf[loc++] = c; if (loc == bufsize) err("Line is too long"); } if (c == EOF) return NULL; buf[loc] = 0; if (c == '\r') { c = getc(mpfile); if (c != '\n') ungetc(c, mpfile); } lnno++; return buf; } /* Return nonzero if a prefix of string s matches the null-terminated string t * and the next character is not a letter of an underscore. */ int match_str (char *s, char *t) { while (*t!=0) { if (*s!=*t) return 0; s++; t++; } switch (*s) { case 'a': case 'c': case 'd': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'w': case 'x': case 'y': case 'z': case '_': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'b': case 'e': case 'v': return 0; default: return 1; } } /* This function tries to express s as the concatenation of three strings * b, t, a, with the global pointers bb, tt, and aa set to the start of the * corresponding strings. String t is either a quote mark, a percent sign, * or an alphabetic token "btex", "etex", or "verbatimtex". (An alphabetic * token is a maximal sequence of letters and underscores.) If there are * several possible substrings t, we choose the leftmost one. If there is * no such t, we set b=s and return 0. */ int getbta (char *s) { int ok=1; /* zero if last character was a-z, A-Z, or _ */ bb = s; for (tt=bb; *tt!=0; tt++) switch (*tt) { case '"': case '%': aa = tt+1; return 1; case 'b': if (ok && match_str(tt,"btex")) { aa = tt+4; return 1; } else ok=0; break; case 'e': if (ok && match_str(tt,"etex")) { aa = tt+4; return 1; } else ok=0; break; case 'v': if (ok && match_str(tt,"verbatimtex")) { aa = tt+11; return 1; } else ok=0; break; case 'a': case 'c': case 'd': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'w': case 'x': case 'y': case 'z': case '_': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': ok = 0; break; default: ok = 1; } aa = tt; return 0; } void copytex(void) { char *s; /* where a string to print stops */ char c; while (*aa==' ' || *aa=='\t') aa++; if (*aa==0) if ((aa=getline())==NULL) err("btex section does not end"); do { if (*aa==0) if ((aa=getline())==NULL) err("btex section does not end"); else printf("\n"); if (getbta(aa) && *tt=='e') { s = tt-1; while (s>=bb && (*s==' ' || *s=='\t')) s--; s++; } else { if (*tt=='b') err("btex in TeX mode"); if (*tt=='v') err("verbatimtex in TeX mode"); s = aa; } c = *s; *s = 0; printf("%s", bb); *s = c; } while (*tt!='e'); } void do_line(void) { aa = buf; while (getbta(aa)) if (*tt=='%') break; else if (*tt=='"') { do if (!getbta(aa)) err("string does not end"); while (*tt!='"'); } else if (*tt=='b') { if (texcnt++ ==0) printf(pretex1,lnno,mpname); else printf(pretex,lnno,mpname); copytex(); printf("%s",posttex); } else if (*tt=='v') { if (verbcnt++ ==0 && texcnt==0) printf(preverb1,lnno,mpname); else printf(preverb,lnno,mpname); copytex(); printf("%s",postverb); } else err("unmatched etex"); } int main(int argc, char **argv) { int mode; if (argc == 1) { fputs ("mpto: Need exactly one file argument.\n", stderr); fputs ("Try `mpto --help' for more information.\n", stderr); exit(1); } else if (argc > 1 && (strcmp (argv[1], "--help") == 0 || strcmp (argv[1], "-help") == 0)) { fputs ("Usage: mpto [-tex|-troff] MPFILE",stdout); #ifdef AMIGA fputs (" [-E]",stdout); #endif fputs ("\n Strip btex..etex and verbatimtex...etex parts from MetaPost input\n\ file MPFILE, converting to either TeX or troff (TeX by default).\n\ \n\ --help display this help and exit\n\ --version output version information and exit\n",stdout); fputs ("\nEmail bug reports to metapost@tug.org.\n", stdout); exit (0); } else if (argc > 1 && (strcmp (argv[1], "--version") == 0 || strcmp (argv[1], "-version") == 0)) { printf ("mpto 0.99\n\ This program is in the public domain.\n\ Primary author of mpto: John Hobby.\n"); exit (0); } else if (argc == 2) { mpname = argv[1]; mode = 0; #ifdef AMIGA } else if (argc == 3) { if (strcmp (argv[1], "-tex") == 0) { mpname = argv[2]; mode = 0; } else if (strcmp (argv[1], "-troff") == 0) { mpname = argv[2]; mode = 1; } else if (strncmp(argv[2], "-E", 2) || (argv[2]+2 == NULL)) { usage(argv[0]); } else { mpname = argv[1]; freopen(argv[2]+2, "w", stderr); } } else if (argc == 4) { if (strcmp (argv[1], "-tex") == 0) { mode = 0; } else if (strcmp (argv[1], "-troff") == 0) { mode = 1; } else { usage(argv[0]); } if (strncmp(argv[3], "-E", 2) || (argv[3]+2 == NULL)) { usage(argv[0]); } else { mpname = argv[2]; freopen(argv[3]+2, "w", stderr); } #else /* not AMIGA */ } else if (argc == 3) { if (strcmp (argv[1], "-tex") == 0) { mode = 0; } else if (strcmp (argv[1], "-troff") == 0) { mode = 1; } else { usage (argv[0]); } mpname = argv[2]; #endif /* not AMIGA */ } else { usage(argv[0]); } mpfile = fopen(mpname, "r"); if (mpfile==NULL) { fprintf (stderr, "%s: ", argv[0]); perror (mpname); exit (1); } /* This is far from elegant, but life is short. */ if (mode == 0) { predoc = tex_predoc; postdoc = tex_postdoc; pretex1 = tex_pretex1; pretex = tex_pretex; posttex = tex_posttex; preverb1 = tex_preverb1; preverb = tex_preverb; postverb = tex_postverb; } else { predoc = troff_predoc; postdoc = troff_postdoc; pretex1 = troff_pretex1; pretex = troff_pretex; posttex = troff_posttex; preverb1 = troff_preverb1; preverb = troff_preverb; postverb = troff_postverb; } printf("%s",predoc); while (getline()!=NULL) do_line(); printf("%s",postdoc); exit(0); }