/* * dvi2tty * Copyright (C) 2003 Marcel J.E. Mol * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /* * Include files */ #include "dvi2tty.h" #if defined(VMS) # include unixio #endif #if defined(THINK_C) # include # include "macintosh.h" #endif #if defined(WIN32) && defined(KPATHSEA) #undef fopen #define fopen fsyscp_fopen #endif /* * Constant definitons */ /*-----------------------------------------------------------------------*/ /* The following constants may be toggled before compilation to */ /* customize the default behaviour of the program for your site. */ /* Whichever their settings are, the defaults can be overridden at */ /* runtime. */ /*-----------------------------------------------------------------------*/ #define DEFSCAND FALSE /* default is not Scandinavian, toggle this if */ /* you have terminals with Scand. nat. chars */ #define DEFLATIN1 FALSE /* default is no latin1, toggle this if you */ /* have terminals with latin1 chars */ #define WANTPAGER TRUE /* default: try to pipe through a pager (like */ /* more) if stdout is tty and no -o switch */ #define DEFPAGER "more" /* CHANGE TO YOUR LOCAL PAGER */ /*------------------ end of customization constants ---------------------*/ #if defined(MSDOS) || defined(VMS) || defined(AMIGA) #define OPTSET "haJweEpPousltvbcANUC" /* legal options */ #define OPTWARG "weEpPovb" /* options with argument */ #else #define OPTSET "haJweEpPousqlfFtvbcANUC" /* legal options */ #define OPTWARG "weEpPoFvb" /* options with argument */ #endif /* * USAGE CODES */ #define wrnge 1 /* width switch arg out of range */ #define ign 2 /* ignore cause, print 'Usage:..' */ #define nan 3 /* not a number where one expected */ #define gae 4 /* garbage at end */ #define bdlst 5 /* bad page-numberlist */ #define onef 6 /* only one dvifile allowed */ #define bdopt 7 /* bad option */ #define onepp 8 /* only one page list allowed */ #define noarg 9 /* argument expected */ #define confl 10 /* -J, -N, -A, and -U conflict */ #define incone 11 /* inconsistent output encoding */ #if defined(THINK_C) #define nored 100 /* if no input file, redirect stdin */ #endif /* * Variable definitions */ const char *dvi2tty = "@(#) dvi2tty.c " VERSION " 20160305 M.J.E. Mol (c) 1989-2010, and contributors (c) -2016"; printlisttype * currentpage; /* current page to print */ printlisttype * firstpage; /* first page selected */ printlisttype * lastpage; /* last page selected */ FILE * DVIfile; FILE * output; bool outputtofile; /* tells if output goes to file or stdout */ #if defined(THINK_C) bool inputfromfile; /* tells if input comes from file or stdin */ #endif int ttywidth; /* max nr of chars per printed line */ int espace; /* to fake calcs with ttywidth */ long foo; /* utility variable, "register" */ #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) && !defined(AMIGA) bool pager; /* tells if output is piped to a pager */ const char * path; /* name of the pager to run */ #endif char * progname; /* our name */ int Argc; char ** Argv; char * DVIfilename; const char * OUTfilename; char optch; /* for option handling */ /* * Function declarations */ #if defined(MSDOS) void setoption (const char *); void getargs (void); void getpages (int, const char *); void plcnxt (int); void getfname (const char *); int getinteger(int *, int *, const char *); int getlong (long *, int *, const char *); void usage (int); #else # if defined(VMS) main (int argc, char ** argv); # endif void setoption (const char * optarg); void getargs (void); void getpages (int j, const char * str); void plcnxt (int pagnr); void getfname (const char * str); int getinteger(int * dest, int * j, const char * str); int getlong (long * dest, int * j, const char * str); void usage (int uerr); #endif /****************************************************************************/ /* */ /* M A I N */ /* */ /****************************************************************************/ #if defined(VMS) main(int argc, char **argv) #else int main(int argc, char **argv) #endif { #if defined(WIN32) && defined(KPATHSEA) char *enc; #endif #if defined(THINK_C) argc = process_dvi_command_line(&argv); #endif progname = *argv; Argc = argc; Argv = argv; #if defined(WIN32) && defined(KPATHSEA) kpse_set_program_name(argv[0], "dvi2tty"); enc = kpse_var_value("command_line_encoding"); get_command_line_args_utf8(enc, &Argc, &Argv); #endif #ifdef WIN32 set_enc_string ("sjis", "default"); #else set_enc_string (NULL, "default"); #endif getargs(); /* read command line arguments */ #if defined(THINK_C) if (inputfromfile) { #endif #if defined(MSDOS) || defined(WIN32) if ((DVIfile = fopen(DVIfilename, "rb")) == NULL) #else # if defined(VMS) if ((DVIfile = fopen(DVIfilename, "r","ctx=rec")) == NULL) # else if ((DVIfile = fopen(DVIfilename, "r")) == NULL) # endif #endif errorexit(filop); /* can't open dvifile */ #if defined(THINK_C) } else DVIfile = stdin; #endif if (outputtofile) { /* open the outfile, if needed */ if ((output = fopen(OUTfilename, "w")) == NULL) errorexit(filcr); #if defined(THINK_C) else set_creator((unsigned char*) OUTfilename); #endif #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) pager = FALSE; #endif } else { output = stdout; #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) if (pager && isatty(fileno(output))) { /* try to pipe to a pager */ if ((output = popen(path, "w")) == NULL) /* get pipe to pager */ errorexit(pipcr); /* make output to output */ } else pager = FALSE; #endif } dvimain(); #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) if (pager) pclose(output); /* close pipe to pager */ #endif exit(0); } /* main */ /* * GETARGS -- Process options from command line and from environment. */ void getargs(void) { const char *str; char *envp; bool DVIfound; /* if a dvi filename found */ #if !defined(THINK_C) if (Argc <= 1) usage(ign); #endif pageswitchon = FALSE; /* show all pages */ sequenceon = FALSE; /* selected pages are TeX-numbered */ outputtofile = FALSE; /* write to stdout */ #if defined(THINK_C) inputfromfile = FALSE; /* read from stdin */ #endif #if !defined(MSDOS) && !defined(VMS) && !defined (THINK_C) && !defined(AMIGA) pager = WANTPAGER; /* want paging, compile time option */ #endif accent = TRUE; /* show all accent etc. as extra char */ ttfont = FALSE; /* assume tt font (verbatim mode) */ noffd = FALSE; /* print formfeed between pages */ scascii = DEFSCAND; /* scandinavian, compile time option */ latin1 = DEFLATIN1; /* latin1 support, compile time option */ utf8 = FALSE; /* print by utf encoding */ noligaturefi = FALSE; /* do not use ligature for ff,fi,fl,ffi,ffl */ ttywidth = 80; /* default terminal width */ espace = 0; /* to fake ttywith calcs */ DVIfound = FALSE; printfont = FALSE; /* do not print font switches */ compose = TRUE; /* try to compose a combining character sequence */ allchar = FALSE; /* do not put out all characters */ #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) && !defined(AMIGA) if ((path = getenv("PAGER")) == NULL) /* find default pathname of page */ path = DEFPAGER; /* program in case paging is wanted */ #endif /* * * With VAX-C under VMS getenv normally searches the environment array * looking for the variables HOME, TERM, PATH, and USER. In certain * situations getenv attempts to first perform a logical name translation * if none of the environment array strings are matched and then trying * to translate a CLI symbol. Unfortunately we need a CLI symbol defined * as; * * dvi2tty :== $path:dvi2tty.exe * * to invoke dvi2tty with command line arguments as it would be invoked * under Unix. So we use the logical DVI$DVI2TYY as the environment * variable from which options may be set. * */ /* * First process environment variable. */ #if defined(VMS) if ((envp = getenv("DVI$DVI2TTY")) != NULL) { #else if ((envp = getenv("DVI2TTY")) != NULL) { /* } keep vi happy */ #endif while (*envp == ' ') envp++; while (*envp) { /* environment var args */ if (strchr(OPTSET, optch = *envp++) != NULL) { /* * we always pass one option, and arrange for optarg ourselfes, * so setoption does not mesh up Argv */ if (strchr(OPTWARG, optch) != NULL) { while (*envp == ' ') envp++; if (*envp == '\0') usage(noarg); str = envp; /* str points to optarg */ while ((*envp != ' ') && (*envp != '\0')) envp++; /* set envp just after optarg */ if (*envp != '\0') *envp++ = '\0'; /* end optarg string */ } else str = ""; setoption(str); } else usage(bdopt); while (*envp == ' ') envp++; } } /* * Now process command line options. */ while (--Argc > 0) { /* command line args */ str = *++Argv; if (*str != '-') { /* argument is not an option */ if (DVIfound) /* only one dvi file allowed */ usage(onef); getfname(str); #if defined(THINK_C) inputfromfile = #endif DVIfound = TRUE; } else if (strchr(OPTSET, optch = *++str) != NULL) { str++; /* point to rest of argument if any */ if ((strchr(OPTWARG, optch) != NULL) && (*str == '\0')) { if (--Argc <= 0) usage(noarg); str = *++Argv; } setoption(str); } else usage(bdopt); } if (!DVIfound) #if defined(THINK_C) /* Allow use of stdin for */ if (isatty(fileno(stdin))) usage(nored); /* Mac, if redirected */ #else usage(ign); #endif return; } /* getargs */ /* * SETOPTION -- Process an option. */ void setoption(const char *optarg) { int j = 0; while (strchr(OPTSET, optch) != NULL) { switch (optch) { case 'h' : usage(ign); break; #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) && !defined(AMIGA) case 'q' : pager = FALSE; break; case 'f' : pager = TRUE; break; case 'F' : pager = TRUE; path = optarg; j = strlen(optarg); break; #endif case 'J' : jautodetect = TRUE; break; case 'U' : uptex = TRUE; japan = TRUE; /* upTeX */ jautodetect = FALSE; enable_UPTEX(true); set_enc_string (NULL, UPTEX_INTERNAL_ENC); break; case 'A' : asciip = TRUE; japan = TRUE; /* ASCII pTeX */ jautodetect = FALSE; set_enc_string (NULL, PTEX_INTERNAL_ENC); break; case 'N' : nttj = TRUE; japan = TRUE; /* NTT jTeX */ jautodetect = FALSE; set_enc_string (NULL, JTEX_INTERNAL_ENC); break; case 'E' : switch (optarg[0]) { case 'e' : set_enc_string ("euc", NULL); break; case 's' : set_enc_string ("sjis", NULL); break; case 'j' : set_enc_string ("jis", NULL); break; case 'u' : utf8 = TRUE; set_enc_string ("utf8", NULL); if (optarg[1]=='1') { noligaturefi = TRUE; j++; } break; default : usage(noarg); } j++; break; case 't' : ttfont = TRUE; break; case 'l' : noffd = TRUE; break; case 's' : scascii ^= 1; break; case 'u' : latin1 ^= 1; break; case 'a' : accent = FALSE; break; case 'C' : compose = FALSE; break; case 'c' : allchar = TRUE; break; case 'P' : sequenceon = TRUE; /* fall through */ case 'p' : if (pageswitchon) usage(onepp); getpages(j, optarg); break; case 'w' : if (getinteger(&ttywidth, &j, optarg)) usage(nan); if (optarg[j] != '\0') usage(gae); if ((ttywidth < 16) || (ttywidth > MAXTERMWIDTH)) usage(wrnge); break; case 'e' : if (getinteger(&espace, &j, optarg)) usage(nan); if (optarg[j] != '\0') usage(gae); break; case 'v' : if (getlong(&lineheight, &j, optarg)) usage(nan); if (optarg[j] != '\0') usage(gae); /* lineheight *= 65536L; */ /* want to specify in pt, but have no getfloat */ break; case 'o' : OUTfilename = optarg; outputtofile = TRUE; j = strlen(optarg); break; case 'b' : printfont = TRUE; delim = optarg; if (!strlen(optarg)) printfont = FALSE; break; default : usage(bdopt); } if ((optch = optarg[j++]) == '\0') break; if ( (optarg[j] == '\0') && (strchr(OPTWARG, optch) != NULL) ) { if (--Argc <= 0) usage(noarg); optarg = *++Argv; j = 0; } } /* Option conflict */ if ((asciip && uptex) || (nttj && (asciip || uptex)) || (jautodetect && (nttj || asciip || uptex))) { usage(confl); } if (((jautodetect || asciip || uptex || nttj || utf8) && (scascii || latin1)) || (scascii && latin1)) { usage(incone); } return; } /* setoption */ /* * GETPAGES -- Getr a list of pages to print. */ void getpages(int j, const char *str) { int i, c; int num; pageswitchon = TRUE; if ((firstpage = (printlisttype *) malloc(sizeof(printlisttype))) == NULL) { perror("firstpage"); exit(1); } firstpage->all = FALSE; firstpage->nxt = nil; firstpage->pag = 0; lastpage = firstpage; currentpage = firstpage; if (getinteger(&num, &j, str)) usage(nan); plcnxt((int) num); while (str[j]) { c = str[j]; if (c == ',' || c == ':') { j++; if (getinteger(&num, &j, str)) usage(nan); } else break; if (c == ',') plcnxt(num); else { if (currentpage->pag < 0) { if (num > 0) { currentpage->all = TRUE; plcnxt(num); } else if (num < currentpage->pag) for (i = currentpage->pag - 1; i >= num; i--) plcnxt(i); else usage(bdlst); } else { if (num < currentpage->pag) usage(bdlst); for (i = currentpage->pag + 1; i <= num; i++) plcnxt(i); } } } if ((str[j] != ' ') && (str[j] != '\0')) { usage(gae); } currentpage = firstpage; return; } /* getpages */ /* * PLCNXT -- Place page-nr next in list. */ void plcnxt(int pagnr) { currentpage = lastpage; currentpage->pag = pagnr; if ((lastpage = (printlisttype *) malloc(sizeof(printlisttype))) == NULL) { perror("lastpage"); exit(1); } lastpage->all = FALSE; lastpage->nxt = nil; lastpage->pag = 0; currentpage->nxt = lastpage; return; } /* plcnxt */ /* * GETFNAME -- {Make sure we have a .dvi filename. */ void getfname(const char *str) { int i; i = strlen(str); if (i == 0) usage(ign); if ((DVIfilename = (char *) malloc(i+5)) == NULL) { perror("DVIfilename"); exit(1); } strcpy(DVIfilename, str); #ifdef KPATHSEA if (!kpse_readable_file(DVIfilename)) #else if ((i < 5) || strcmp(str+i-4, ".dvi")) #endif strcat(DVIfilename, ".dvi"); return; } /* getfname */ /* * GETINTEGER -- Convert ascii to an integer. I'm sure there is a library * call for it. */ int getinteger(int *dest, int *j, const char *str) { int cum; int sgn; char ch; ch = str[*j]; if (ch == '-') { sgn = -1; ch = str[++(*j)]; } else sgn = 1; if ((ch >= '0') && (ch <= '9')) { cum = 0; while ((ch >= '0') && (ch <= '9')) { cum = cum*10 + ch - '0'; ch = str[++(*j)]; } *dest = sgn * cum; return 0; /* return ok */ } return 1; /* return error */ } /* getinteger */ /* * GETLONG -- Convert ascii to a long. I'm sure there is a library * call for it. */ int getlong(long *dest, int *j, const char *str) { long cum; int sgn; char ch; ch = str[*j]; if (ch == '-') { sgn = -1; ch = str[++(*j)]; } else sgn = 1; if ((ch >= '0') && (ch <= '9')) { cum = 0; while ((ch >= '0') && (ch <= '9')) { cum = cum*10L + ch - '0'; ch = str[++(*j)]; } *dest = (long) sgn * cum; return 0; /* return ok */ } return 1; /* return error */ } /* getinteger */ /* * ERROREXIT -- Exit program with an erro message. */ void errorexit(int errorcode) { fprintf(stderr, "%s: ", progname); switch (errorcode) { case illop : fprintf(stderr, "Illegal op-code found: %d\n", opcode); break; case stkof : fprintf(stderr, "Stack overflow\n"); break; case stkuf : fprintf(stderr, "Stack underflow\n"); break; case stkrq : fprintf(stderr, "Cannot create dvi stack\n"); break; case lnerq : fprintf(stderr, "Cannot allocate memory\n"); break; case badid : fprintf(stderr, "Id-byte is not correct: %d\n ", opcode); break; case bdsgn : fprintf(stderr, "Bad signature: %d (not 223)\n", (int) foo); break; case fwsgn : fprintf(stderr, "%d signature bytes (min. 4)\n", (int) foo); break; case nopre : fprintf(stderr, "Missing preamble\n"); break; case nobop : fprintf(stderr, "Missing beginning-of-page command\n"); break; case nopp : fprintf(stderr, "Missing post-post command\n"); break; case bdpre : fprintf(stderr, "Preamble occured inside a page\n"); break; case bdbop : fprintf(stderr, "BOP-command occured inside a page\n"); break; case bdpst : fprintf(stderr, "Postamble occured before end-of-page\n"); break; case bdpp : fprintf(stderr, "Postpost occured before post-command\n"); break; case nopst : fprintf(stderr, "Missing postamble\n"); break; case illch : fprintf(stderr, "Character code out of range, 0..127\n"); break; case filop : fprintf(stderr, "Cannot open dvifile\n"); break; case filcr : fprintf(stderr, "Cannot create outfile\n"); break; #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) && !defined(AMIGA) case pipcr : fprintf(stderr, "Cannot create pipe to pager\n"); break; #endif default : fprintf(stderr, "Unkown error code\n"); break; }; if (outputtofile) #if defined(VMS) remove(OUTfilename); #else unlink(OUTfilename); #endif exit(errorcode); } /* errorexit */ /* * USAGE -- Print the usage info. Also print a warning/error message * if needed. */ void usage(int uerr) { if (jautodetect || nttj || asciip || uptex) fprintf(stderr, "%s (%s) %s", Progname, get_enc_string(), Copyright); else fprintf(stderr, "%s %s", Progname, Copyright); if (uerr != ign) { fprintf(stderr,"\n%s: ", progname); switch (uerr) { case wrnge : fprintf(stderr, "width arg out of range:16-%d", MAXTERMWIDTH); break; case nan : fprintf(stderr, "numeric argument expected for option %c", optch); break; case gae : fprintf(stderr, "garbage in argument for option %c", optch); break; case bdlst : fprintf(stderr, "mal-formed list of pagenumbers"); break; case onef : fprintf(stderr, "only one infile argument allowed"); break; case noarg : fprintf(stderr, "option argument expected for option %c", optch); break; case bdopt : fprintf(stderr, "bad option %c", optch); break; case onepp : fprintf(stderr, "only one pagelist allowed"); break; case confl : fprintf(stderr, "-J, -N, -A, and -U are mutually exclusive"); break; case incone : fprintf(stderr, "output encoding is not consistent"); break; #if defined(THINK_C) case nored : fprintf(stderr, "\nIf no input file is given in\ command string,\n\Standard Input must be redirected with the radio button."); break; #endif default : fprintf(stderr, "unknown usage error"); break; } fprintf(stderr, "\n"); } fprintf(stderr, "\n%s\n\n", dvi2tty); #if defined(THINK_C) fprintf(stderr, "Usage: %s [ options ] [[.dvi]]\n", progname); fprintf(stderr, "Read input from , else read from Standard Input,\ \nwhich must be redirected by means of the radio button.\n"); #else fprintf(stderr, "Usage: %s [ options ] [.dvi]\n", progname); #endif fprintf(stderr, "Options are:\n"); fprintf(stderr, " -ofile Write output to file, else write to stdout.\n"); fprintf(stderr, " -plist Print pages whose TeX-page-number are in list.\n"); fprintf(stderr, " -Plist Print pages whose sequential number are in list.\n"); fprintf(stderr, " -wn Print the lines with width n characters, default 80.\n"); fprintf(stderr, " -vn Use n for vertical line height, default 450000.\n"); fprintf(stderr, " -evalue Add/Substract this value for spacing (-20..20)\n"); #if !defined(MSDOS) && !defined(VMS) && !defined(THINK_C) && !defined(AMIGA) fprintf(stderr, " -f Try to pipe to a pager if output is a tty"); if (WANTPAGER) fprintf(stderr, " (default).\n"); else fprintf(stderr, ".\n"); fprintf(stderr, " -q Don't try to pipe to a pager"); if (WANTPAGER) fprintf(stderr, ".\n"); else fprintf(stderr, " (default).\n"); fprintf(stderr, " -Fprog Pipe output to pager prog.\n"); #endif fprintf(stderr, " -a Remove accents grave etc. from output: \\'{e} -> e.\n"); fprintf(stderr, " -t Assuming that document was made with tt fonts\n"); fprintf(stderr, " -l Write ''^L'' instead of formfeed between pages.\n"); fprintf(stderr, " -s Toggle National Swedish/Finnish characters printed as aaoAAO (default %s).\n", DEFSCAND ? "off" : "on"); fprintf(stderr, " -u Toggle latin1 support (default %s).\n", DEFLATIN1 ? "on" : "off"); fprintf(stderr, " -J Enable auto detect for NTT JTeX, ASCII pTeX, and upTeX (japanese fonts).\n"); fprintf(stderr, " -N Support NTT JTeX dvi.\n"); fprintf(stderr, " -A Support ASCII pTeX dvi.\n"); fprintf(stderr, " -U Support upTeX dvi.\n"); fprintf(stderr, " -Eenc Output multibyte encoding. u:UTF8, e:EUC-JP s:Shift_JIS j:JIS\n" " u1:UTF8 (do not use ligature for ff,fi,fl,ffi,ffl).\n"); fprintf(stderr, " -C Don't try to compose a combining character sequence.\n"); fprintf(stderr, " -c Override -a -u -s and print all characters 0-255.\n"); fprintf(stderr, " -bdelim Print font switch as text: delimcmr10miled\n"); fprintf(stderr, " -h This help message.\n"); fprintf(stderr, "\n If you like this code and want to support is feel free\n to donate at Paypal marcel@mesa.nl. Thanks.\n\n"); exit(uerr); } /* usage */