home *** CD-ROM | disk | FTP | other *** search
- /* ts=2;
- ** $RCSfile: lp.c,v $
- ** $Release$
- ** $Revision: 1.18 $
- ** $Date: 93/01/18 01:27:15 $
- ** $Author: tf $
- **
- ** (c) Copyright 1991,92 Tobias Ferber, All Rights Reserved.
- */
-
- #include <exec/types.h>
- #include <stdio.h>
- #include <exec/memory.h>
-
- /* instead of "memblock.h" */
-
- extern char *alloc_mem(long);
- extern void free_mem(char *);
- extern void free_all(void);
-
- char *whoami; /* who am I? (copy of argv[0]) */
-
- #include <stdarg.h>
-
- void perror(const char *fmt, ...)
- {
- va_list argp;
- va_start(argp,fmt); /* name the last known argument */
- fprintf(stdout,"\r%s: ",whoami);
- vfprintf(stdout,fmt,argp);
- fprintf(stdout,"\n");
- fflush(stdout);
- va_end(argp); /* just to be sure... */
- }
-
- void _abort(void)
- { printf("^C\n\n***BREAK\n");
- free_all();
- exit(1);
- }
-
- #include "strfn.h"
-
- static char rcs_id[] = "$VER: $Id: lp.c,v 1.18 93/01/18 01:27:15 tf Exp $";
-
- #define BANNER &rcs_id[6]
-
- struct jobparm
- { int indent; /* left margin */
- int charct; /* characters per line = bufsize */
- int linect; /* #of lines per page */
- int tabsize; /* 0 = don't convert tabs -> spaces */
- int columns; /* #of columns: width= charct/columns */
- long flags; /* see JPFLAG_XXXX */
- char *leader; /* output line leader */
- int firstpage; /* pageno to start numbering with */
- int lineskip; /* number of lines to be skiped at tof */
- char *infile; /* input filename */
- char *outfile; /* output filename */
- char *tocfile; /* list file filename (table of contents) */
- char *argmem; /* argument buffer */
- long membytes; /* size of allocated argument buffer */
- struct jobparm *next; /* next job to submit */
- };
-
- #define JPFLAG_APPEND (1L) /* append output to print destination */
- #define JPFLAG_REPLACE (1L<<1) /* replace input file by output file */
- #define JPFLAG_PLAIN (1L<<2) /* don't ENV:InitPrinter */
- #define JPFLAG_AUTOLF (1L<<3) /* send CR, no LF for new lines */
- #define JPFLAG_MINI (1L<<4) /* print superscript, subscript... */
- #define JPFLAG_USEFF (1L<<5) /* send FF, not a sequence of LF */
- #define JPFLAG_CLEANUP (1L<<6) /* delete SPC/TAB at the end of a line */
- #define JPFLAG_HEADING (1L<<7) /* print a page header */
- #define JPFLAG_FOOTING (1L<<8) /* print page footings */
- #define JPFLAG_DOUBLESIDED (1L<<9) /* flag for type of page numbering */
- #define JPFLAG_FEEDOUT (1L<<10) /* feed out the last sheet of a file */
-
- #define JP_APPEND(f) (((f)&JPFLAG_APPEND)==JPFLAG_APPEND)
- #define JP_REPLACE(f) (((f)&JPFLAG_REPLACE)==JPFLAG_REPLACE)
- #define JP_PLAIN(f) (((f)&JPFLAG_PLAIN)==JPFLAG_PLAIN)
- #define JP_AUTOLF(f) (((f)&JPFLAG_AUTOLF)==JPFLAG_AUTOLF)
- #define JP_MINI(f) (((f)&JPFLAG_MINI)==JPFLAG_MINI)
- #define JP_USEFF(f) (((f)&JPFLAG_USEFF)==JPFLAG_USEFF)
- #define JP_CLEANUP(f) (((f)&JPFLAG_CLEANUP)==JPFLAG_CLEANUP)
- #define JP_HEADING(f) (((f)&JPFLAG_HEADING)==JPFLAG_HEADING)
- #define JP_FOOTING(f) (((f)&JPFLAG_FOOTING)==JPFLAG_FOOTING)
- #define JP_DOUBLESIDED(f) (((f)&JPFLAG_DOUBLESIDED)==JPFLAG_DOUBLESIDED)
- #define JP_SINGLESIDED(f) (!(JP_DOUBLESIDED(f)))
- #define JP_FEEDOUT(f) (((f)&JPFLAG_FEEDOUT)==JPFLAG_FEEDOUT)
-
- /*
- * \a = $07 [BELL]
- * \b = $08 [BACKSPACE]
- * \t = $09 [TAB]
- * \n = $0a [LF]
- * \v = $0b
- * \f = $0c [FF]
- * \r = $0d [CR]
- * \x = $ff [EOF]
- */
-
- #define TAB '\t'
- #define LF '\n'
- #define CR '\r'
- #define FF '\f'
-
- #define SUPERSCRIPT "\15\33[2v"
- #define SUBSCRIPT "\12\33[4v"
-
- void newline(FILE *fp, long flags)
- { static BOOL ss=FALSE; /* first newline changes to subscript */
- if(JP_MINI(flags))
- { fprintf(fp,(ss)?(SUPERSCRIPT):(SUBSCRIPT));
- ss=!ss;
- }
- else if(JP_AUTOLF(flags))
- fputc(CR,fp);
- else
- fputc(LF,fp);
- }
-
- #define term_write(num) \
- do \
- { fprintf(stdout," %ld\r",num); \
- fflush(stdout); \
- } while(0);
-
- #define term_clear \
- do \
- { fprintf(stdout," \r"); \
- fflush(stdout); \
- } while(0);
-
- #define ENV_VOLUME "ENV:"
- #define ENV_LPOPTS "ENV:LPOPTS"
- #define INITPRINTER "ENV:InitPrinter"
- #define INITMINI "\33c\33#4\33[2w\33[4w\33[0z\33[2v"
- #define INITNOMINI "\33#1" /* turn off all special modi */
- #define PRINTERNAME "PRT:"
- #define LOGFILENAME "lp.log"
- #define DEFOUT "lp.out"
- #define TEMPNAME "lp$col.tmp"
- #define USAGE "USAGE: lp [options] [infile] [@tocfile]"
-
- #define DEFCHARCT 80L
- #define DEFINDENT 0L
- #define DEFTABSIZE 8L
- #define DEFLINECT 66L
- #define DEFREFRESH DEFLINECT
- #define DEFJPFLAGS JPFLAG_CLEANUP
-
-
- static char *jobreport[]= /* not used */
- { "Print job terminated without errors.", /* 0 */
- "Fatal-Error: AllocMem() failed, ran out of memory.", /* 1 */
- "Nothing to print.", /* 2 */
- "Unable to open input file.", /* 3 */
- "Error: Illegal or unknown directive.", /* 4 */
- "Unable to open print destination.", /* 5 */
- "Fatal-Error: source of error unknown.", /* 6 */
- };
-
- #define STATE_OKAY 0L
- #define STATE_NOMEM 1L
- #define STATE_NOFILE 2L
- #define STATE_ERRFILE 3L
- #define STATE_ERROPT 4L
- #define STATE_ERRPRT 5L
- #define STATE_FATAL 6L
-
- struct jobstate
- { long inln; /* lines of input */
- long outln; /* lines of output */
- long wraps; /* #of performed word wraps */
- long cracks; /* #of broken lines */
- long cleanups; /* #of invisible chars removed */
- long fillups; /* #of empty lines added */
- };
-
- char *alloc_argmem(jobparm,bytesize)
- struct jobparm *jobparm;
- long bytesize;
- { char *argmem;
- argmem= (char *)alloc_mem(bytesize);
- if(argmem)
- { jobparm->argmem= argmem;
- jobparm->membytes= bytesize;
- }
- return(argmem);
- }
-
- char *load_argfile(jobparm,filename)
- struct jobparm *jobparm;
- char *filename;
- { FILE *fp;
- char *argmem=(char *)NULL;
- if(filename)
- { long fsize=0;
- fp=fopen(filename,"r");
- if(fp)
- { fseek(fp, 0L, 2L); /* OFFSET_END = 2L */
- fsize=ftell(fp);
- if(fsize)
- { fseek(fp, 0L, 0L);
- argmem= alloc_argmem(jobparm, 1+fsize); /* + EOF */
- if(argmem)
- { fread(argmem, sizeof(char), fsize, fp);
- argmem[fsize]= EOF;
- }
- }
- fclose(fp);
- }
- }
- return(argmem);
- }
-
- /*
- * Amiga options: /S Switch
- * /K Keyword
- * /N Number
- * /T Toggle
- * /A Required
- * /F Rest of line
- * /M Multiple strings
- *
- * Note that there *MUST* be a space character following the option string!
- */
-
- static char *howtouse[] = {
-
- "INDENT", "-i", "<indent> ", "set indention, left margin (default: 0)",
- "WIDTH", "-w", "<charct> ", "set page width, right margin (default: 80)",
- "HEIGHT", "-h", "<linect> ", "set page height in #of lines per page (default: 66)",
- "FILE", "-u", "<infile> ", "force next argument to be the input filename",
- "TO", "-o", "<outfile>", "set output device or file (default is PRT:)",
- "APPEND", "-a", " ", "append output to print destination (default for @tocfiles)",
- "NOAPPEND", "+a", " ", "overwrite print destination (default)",
- "REPLACE", "-r", " ", "replace the input file by the output file",
- "TABSIZE", "-t", "[tabsize]", "set tabsize and convert tabs to spaces",
- "USETAB", "+t", " ", "send tabs, don't convert tabs to spaces",
- "CRONLY", "-e", " ", "print with AUTO CR/LF option (send CR only)",
- "LFONLY", "+e", " ", "turn off AUTO CR/LF option (send normal LF)",
- "USEFF", "-f", " ", "use formfeed (FF) characters for new pages",
- "NOFF", "+f", " ", "convert a formfeed into a sequece of linefeeds (default)",
- "PLAIN", "-p", " ", "print plain, don't (ENV:) init printer",
- "NOPLAIN", "+p", " ", "add ENV:InitPrinter to the top of the file (default)",
- "MINI", "-m", " ", "print one line superscript, next subscript...",
- "NOMINI", "+m", " ", "turn off MINI option '-m' (default)",
- "SKIPTOPAGE", "-b", "<pageno> ", "begin printing with the first line of page <pageno>",
- "SKIPTOLINE", "-s", "<lineno> ", "start with line <lineno> of the input file (default: 1)",
- "NOCLEANUP", "-d", " ", "don't delete spaces or tabs at the end of a line",
- "CLEANUP", "+d", " ", "delete spaces or tabs at the end of a line (default)",
- "LEADER", "-l", "<string> ", "print <string> in front of each output line",
- "NOLEADER", "+l", " ", "do not print any leading string",
- "HEADER", "-n", " ", "print page header (filename, date)",
- "NOHEADER", "+n", " ", "turn off HEADER option '-n', don't print any header (default)",
- "SINGLESIDED", "-1", "[pageno] ", "single sided page numbering beginning with page [pageno]",
- "DOUBLESIDED", "-2", "[pageno] ", "page numbering for double sided output.",
- "NOFOOTINGS", "+0", " ", "no page numbering, no footings (default)",
- "COLUMNS", "-c", "<columns>", "set #of columns of equal width (default: 1, max: 2)",
- "FEEDOUT", "-x", " ", "expand each file via LF to fill up its last sheet",
- "NOFEEDOUT", "+x", " ", "do not add anything to the end of file (default)",
- "WITH", "@", "<tocfile>", "print a list of files (each with it's arguments)",
- NULL, NULL, NULL, NULL
- };
-
- /*
- * arglist2jobparm() parses argc arguments of given arglist argv[]
- * and fills the jobparm structure accordingly. (no checking!)
- */
-
- void arglist2jobparm(jobparm, argc, argv)
- struct jobparm *jobparm;
- int argc;
- char *argv[];
- { char *arg;
- if(jobparm)
- { while(argc>0)
- { arg=argv[0];
-
- if(isalpha(*arg))
- { char **aopt= &howtouse[0];
- /*while(*aopt && strnicmp(arg,*aopt,strlen(*aopt)))*/
- while(*aopt && stricmp(arg,*aopt))
- aopt= &aopt[4];
- if(*aopt) arg= aopt[1];
- /*if(*aopt) printf("AmigaDOS option %s changed to '%s'\n",aopt[0],aopt[1]);*/
- }
-
- if(*arg=='-')
- { arg++;
- switch(*arg)
- {
- /* -1 */ case '1':
- if(arg[1]) jobparm->firstpage= atol(arg+1);
- else if('0'<=argv[1][0] && argv[1][0]<='9') /* isdigit(n) ? */
- { argv++;
- argc--;
- jobparm->firstpage= atol(argv[0]);
- }
- jobparm->flags |= JPFLAG_FOOTING;
- jobparm->flags &= ~JPFLAG_DOUBLESIDED;
- break;
- /* -2 */ case '2':
- if(arg[1]) jobparm->firstpage= atol(arg+1);
- else if('0'<=argv[1][0] && argv[1][0]<='9') /* isdigit(n) ? */
- { argv++;
- argc--;
- jobparm->firstpage= atol(argv[0]);
- }
- jobparm->flags |= JPFLAG_FOOTING;
- jobparm->flags |= JPFLAG_DOUBLESIDED;
- break;
- /* -a */ case 'a': case 'A':
- jobparm->flags |= JPFLAG_APPEND;
- break;
- /* -b */ case 'b': case 'B':
- if(arg[1]) jobparm->lineskip= -atol(arg+1);
- else
- { argv++;
- argc--;
- jobparm->lineskip= -atol(argv[0]);
- }
- break; /* negative lineskip will be converted to pageskip later */
- /* -c */ case 'c': case 'C':
- if(arg[1]) jobparm->columns= atol(arg+1);
- else
- { argv++;
- argc--;
- jobparm->columns= atol(argv[0]);
- }
- break;
- /* -d */ case 'd': case 'D':
- jobparm->flags &= ~JPFLAG_CLEANUP;
- break;
- /* -e */ case 'e': case 'E':
- jobparm->flags |= JPFLAG_AUTOLF;
- break;
- /* -f */ case 'f': case 'F':
- jobparm->flags |= JPFLAG_USEFF;
- break;
- /* -h */ case 'h': case 'H':
- if(arg[1]) jobparm->linect= atol(arg+1);
- else
- { argv++;
- argc--;
- jobparm->linect= atol(argv[0]);
- }
- break;
- /* -i */ case 'i': case 'I':
- if(arg[1]) jobparm->indent= atol(arg+1);
- else
- { argv++;
- argc--;
- jobparm->indent= atol(argv[0]);
- }
- break;
-
- /* -l */ case 'l': case 'L':
- if(arg[1]) jobparm->leader= &arg[1];
- else
- { argv++;
- argc--;
- jobparm->leader= argv[0];
- }
- break;
- /* -m */ case 'm': case 'M':
- jobparm->flags |= JPFLAG_MINI;
- break;
- /* -n */ case 'n': case 'N':
- jobparm->flags |= JPFLAG_HEADING;
- break;
- /* -o */ case 'o': case 'O':
- if(arg[1]) jobparm->outfile= &arg[1];
- else
- { argv++;
- argc--;
- jobparm->outfile= argv[0];
- }
- break;
- /* -p */ case 'p': case 'P':
- jobparm->flags |= JPFLAG_PLAIN;
- break;
- /* -r */ case 'r': case 'R':
- jobparm->outfile= DEFOUT;
- jobparm->flags &= ~JPFLAG_APPEND;
- jobparm->flags |= JPFLAG_REPLACE;
- break;
- /* -s */ case 's': case 'S':
- if(arg[1]) jobparm->lineskip= atol(arg+1);
- else
- { argv++;
- argc--;
- jobparm->lineskip= atol(argv[0]);
- }
- break;
- /* -t */ case 't': case 'T':
- if(arg[1]) jobparm->tabsize= atol(arg+1);
- else if('0'<=argv[1][0] && argv[1][0]<='9') /* isdigit(n) ? */
- { argv++;
- argc--;
- jobparm->tabsize= atol(argv[0]);
- }
- else jobparm->tabsize= DEFTABSIZE;
- break;
- /* -u */ case 'u': case 'U':
- if(arg[1]) jobparm->infile= &arg[1];
- else
- { argv++;
- argc--;
- jobparm->infile= argv[0];
- }
- break;
- /* -w */ case 'w': case 'W':
- if(arg[1]) jobparm->charct= atol(arg+1);
- else
- { argv++;
- argc--;
- jobparm->charct= atol(argv[0]);
- }
- break;
- /* -x */ case 'x': case 'X':
- jobparm->flags |= JPFLAG_FEEDOUT;
- break;
- default:
- perror("Warning: Unknown option `-%c' ignored.",*arg);
- }
- }
- else if(*arg=='+')
- { arg++;
- switch(*arg)
- {
- /* +0 */ case '0':
- jobparm->flags &= ~JPFLAG_FOOTING;
- break;
- /* +a */ case 'a': case 'A':
- jobparm->flags &= ~JPFLAG_APPEND;
- /* +d */ case 'd': case 'D':
- jobparm->flags |= JPFLAG_CLEANUP;
- break;
- /* +e */ case 'e': case 'E':
- jobparm->flags &= ~JPFLAG_AUTOLF;
- break;
- /* +f */ case 'f': case 'F':
- jobparm->flags &= ~JPFLAG_USEFF;
- break;
- /* +l */ case 'l': case 'L':
- jobparm->leader = (char *)NULL;
- break;
- /* +m */ case 'm': case 'M':
- jobparm->flags &= ~JPFLAG_MINI;
- break;
- /* +n */ case 'n': case 'N':
- jobparm->flags &= ~JPFLAG_HEADING;
- break;
- /* +p */ case 'p': case 'P':
- jobparm->flags &= ~JPFLAG_PLAIN;
- break;
- /* +t */ case 't': case 'T':
- jobparm->tabsize= 0;
- break;
- /* +x */ case 'x': case 'X':
- jobparm->flags &= ~JPFLAG_FEEDOUT;
- break;
- default:
- perror("Warning: Unknown option '+%c' ignored.",*arg);
- }
- }
- else if(*arg=='@')
- { if(arg[1])
- jobparm->tocfile= &arg[1];
- else
- { argv++;
- argc--;
- jobparm->tocfile= argv[0];
- }
- jobparm->flags |= JPFLAG_APPEND;
- }
- else if(*arg > ' ')
- jobparm->infile= arg;
- argc--;
- argv++;
- }
- }
- }
-
- #define MAXARGS 50 /* maximum #of arguments per line */
-
- /*
- * make_arglist() converts given argument string `args' into a list of argv[]
- * and a #of args `argc'.
- */
-
- char *make_arglist(args, argc, argv, line)
- char *args;
- int *argc;
- char *argv[];
- long *line;
- { int ac=0, /* argument counter */
- smode=0; /* scanner mode: 0= outer arg mode
- * 1= inner argument mode
- * 2= inner quote mode
- * 3= EOL found
- * 4= EOF reached
- */
- char *t=args; /* pointer to the beginning of the current arg string */
-
- while(smode<3)
- {
- switch(*args)
- { case ';':
- if(smode<2)
- { *args='\0';
- while(*args!='\n' && *args!=EOF) /* ';' == EOL comment leader */
- args++;
- }
- else ++args;
- break;
- case '\n': case EOF:
- (*line)++; /* since our caller begins counting with line=0 */
- if(smode==2)
- { perror("Warning: Unmatched quote found.");
- ac= -1; /* error! */
- *args= EOF; /* stop scanner (return NULL) */
- }
- else if(smode==1)
- argv[ac++]=t;
- if(*args==EOF) smode=4;
- else
- { if(ac>0) smode=3;
- }
- *args++='\0';
- t=args;
- break;
- case '\"':
- if(smode>0)
- { argv[ac++]=t;
- *args='\0';
- if(smode==1) smode=2;
- else smode=0;
- }
- else smode=2;
- t=++args;
- break;
- case ' ': case '\t':
- if(smode<2)
- { if(smode==1)
- { argv[ac++]=t;
- *args='\0';
- }
- t=&args[1];
- smode=0;
- }
- ++args;
- break;
- default:
- if(smode==0) smode=1;
- ++args;
- break;
- }
- }
-
- *argc=ac;
- return (smode==4) ? (char *)NULL : args;
- }
-
- /*
- * check the settings in a jobparm structure
- */
-
- int check_jobparm(jobparm, line, from)
- struct jobparm *jobparm;
- int line;
- char *from;
- { int state= STATE_OKAY;
- char loc[256]; /* error location */
-
- if(line>0)
- sprintf(loc,"Error line %ld \"%s\"",line,from);
- else
- sprintf(loc,"Error in %s",from);
-
- if(jobparm->charct<1)
- { perror("%s Illegal page width %ld (option -w).",
- loc,jobparm->charct );
- state= STATE_ERROPT;
- }
- if(jobparm->linect<1)
- { perror("%s Illegal page height %d (option -h).",
- loc,jobparm->linect );
- state= STATE_ERROPT;
- }
- if(jobparm->indent<0)
- { perror("%s Negative indention (%ld) not supported.",
- loc,jobparm->indent );
- state= STATE_ERROPT;
- }
- if(jobparm->charct <= jobparm->indent)
- { perror("%s Page width must be > indention!",loc);
- state= STATE_ERROPT;
- }
- if(!(jobparm->outfile && *(jobparm->outfile)))
- { perror("%s No output (device) specified.",loc);
- state= STATE_ERRPRT;
- }
- return(state);
- }
-
- /*
- * tail() returns a pointer to the last jobparm structure in the job-list
- * using a while loop instead of recursion to increase efficiency.
- */
-
- struct jobparm *tail(node)
- struct jobparm *node;
- { while(node->next)
- node= node->next;
- return(node);
- }
-
- /*
- * file2jobparm() converts each line of given file(name) into a jobparm
- * structure and chains the jobparm structures to a list.
- * The head of this chained list (i.e. first line's jobparm structure)
- * will then be chained to the given jobparm structure.
- *
- * NOTE:
- * Given jobparm structure contains the default settings for the whole
- * file. Each new allocated jobparm structure will be initilalized with
- * it's values.
- */
-
- struct jobparm *alloc_jobparm(); /* pre-declaration */
-
- int file2jobparm(jp_base, filename)
- struct jobparm *jp_base;
- char *filename;
- {
- static char *tgraph[256]; /* recursion depth limited to 256 !!! */
- static int tnodect= 0;
- int state= STATE_FATAL;
-
- if(jp_base && filename && *filename)
- { char *filemem;
-
- /* Check the tgraph for non-deterministic recursions. */
-
- int n;
- for(n=0; n<tnodect; n++)
- { if(!stricmp(filename, tgraph[n]))
- { perror("Fatal-Error with \"%s\" Contents is non-deterministic!",
- filename);
- return(STATE_FATAL);
- }
- }
- if(tnodect>=225)
- { perror("Ran out of memory! Recursion depth > 256");
- return(STATE_FATAL);
- }
- tgraph[tnodect++]= filename; /* add the tgraph node */
-
- filemem= load_argfile(jp_base, filename);
- if(filemem)
- { struct jobparm *jobparm= jp_base; /* working pointer */
- char *args=filemem; /* pointer into filemem */
- int argc; /* argument counter */
- char *argv[MAXARGS]; /* argument list */
- long line=0; /* line number for error messages */
- state= STATE_OKAY; /* everything seems okay now */
-
- while(args && (state==STATE_OKAY))
- { jobparm->next= alloc_jobparm(jp_base);
- if(jobparm->next)
- { jobparm= jobparm->next;
- args= make_arglist(args, &argc, argv, &line);
- if(argc<0)
- { perror("Error line %ld \"%s\" Argument scan failed.",
- line,filename);
- return(STATE_FATAL);
- }
- arglist2jobparm(jobparm,argc,argv);
- state= check_jobparm(jobparm, line, filename);
- if(state==STATE_OKAY)
- { if(jobparm->tocfile && *(jobparm->tocfile))
- {
- /* prevent lp from performing non-deterministric recursions */
- for(n=0; n<tnodect; n++)
- { if(!stricmp(jobparm->tocfile, tgraph[n]))
- { perror("Fatal-Error line %ld \"%s\" Non-deterministic recursion!",
- line,filename);
- return(STATE_FATAL);
- }
- }
- state= file2jobparm(jobparm, jobparm->tocfile);
- }
- jobparm= tail(jobparm);
- }
- }
- else
- { perror("Error line %ld \"%s\" Out of memory!",
- line,filename);
- state=STATE_NOMEM;
- }
- }
- }
- else
- { perror("File-Error: Unable to load \"%s\".",filename);
- state=STATE_NOMEM;
- }
- --tnodect; /* delete the tgraph node */
- }
- return(state);
- }
-
- void free_jobparm(struct jobparm *jobparm)
- { if(jobparm)
- { if(jobparm->next)
- free_jobparm(jobparm->next);
- if(jobparm->argmem && jobparm->membytes)
- free_mem(jobparm->argmem);
- free_mem(jobparm);
- }
- }
- /*
- * allocate jobparm structure and init default values.
- */
-
- struct jobparm *alloc_jobparm(jp_default)
- struct jobparm *jp_default;
- { struct jobparm *jobparm;
-
- jobparm= (struct jobparm *)alloc_mem(sizeof(struct jobparm));
- if(jobparm)
- {
- /* Just to be sure that this is unset: */
-
- jobparm->firstpage = 0; /* => continue with current # */
- jobparm->infile = (char *)NULL; /* which file to print? */
- jobparm->tocfile = (char *)NULL; /* list of files for this job */
- jobparm->argmem = (char *)NULL; /* not allocated yet */
- jobparm->membytes = 0; /* => not set yet */
- jobparm->next = (struct jobparm *)NULL;
-
- if(jp_default)
- { jobparm->indent = jp_default->indent;
- jobparm->charct = jp_default->charct;
- jobparm->linect = jp_default->linect;
- jobparm->tabsize = jp_default->tabsize;
- jobparm->columns = jp_default->columns;
- jobparm->flags = jp_default->flags;
- jobparm->leader = jp_default->leader;
- jobparm->lineskip = jp_default->lineskip;
- jobparm->outfile = jp_default->outfile;
- }
- else
- { jobparm->indent = DEFINDENT; /* left margin */
- jobparm->charct = DEFCHARCT; /* characters per line = bufsize */
- jobparm->linect = DEFLINECT; /* = don't fill pages */
- jobparm->tabsize = 0; /* = don't convert tabs -> spaces */
- jobparm->columns = 1; /* #of columns of equal width */
- jobparm->flags = DEFJPFLAGS; /* default flags */
- jobparm->outfile = PRINTERNAME; /* should be "PRT:" */
-
- if((dltype(ENV_VOLUME)!=DLT_UNKNOWN) && fexist(ENV_LPOPTS))
- file2jobparm(jobparm, ENV_LPOPTS);
- }
- }
- return(jobparm);
- }
-
- #define HEADERLINES 3L
-
- /*
- * make the headerlines and return a pointer to it's static string
- */
-
- #include <time.h>
-
- char *make_heading(jobparm)
- struct jobparm *jobparm;
- { static char header[512];
- int len, maxlen;
-
- /*len = stcgfn(header,jobparm->infile);*/
- /* seperate filename's node.ext */
-
- len= strlen(jobparm->infile);
- strcpy(header,jobparm->infile);
-
- maxlen = jobparm->charct;
-
- if(len>maxlen && maxlen>3)
- strcpy(&header[maxlen-3],"...");
- else if(len+24< maxlen)
- { long t;
- char *s;
- time(&t); /* get #of sec. since 00:00:00 GMT Jan 1, 1970 */
- s= ctime(&t); /* convert to 26 characters ASCII string */
- s[24]='\0'; /* remove '\n' character */
- for(t=len; t<maxlen-24; t++)
- header[t]=' ';
- strcpy(&header[t],s);
- }
- else header[0]='\0';
- strcat(header,"\n\n\n");
- return(header);
- }
-
- /*
- * make the footer lines in the same way
- */
-
- int numdigits(unsigned long x) /* get #of digits in a long */
- { int d=0;
- do
- { x/=10;
- d++;
- } while(x>0);
- return(d);
- }
-
- #define FOOTERLINES 3L
-
- /*
- * make page footings, return a pointer to a static string
- */
-
- char *make_footing(jobparm, pageno)
- struct jobparm *jobparm;
- unsigned long pageno;
- { static char footer[512];
- char fmt[80];
-
- if(JP_SINGLESIDED(jobparm->flags))
- { sprintf(fmt,"\n\n%%%ldld\n",
- (jobparm->charct + numdigits(pageno) -1) /2 );
- sprintf(footer,fmt,pageno);
- }
- else if(pageno%2)
- { sprintf(fmt,"\n\n%%%ldld\n",jobparm->charct);
- sprintf(footer,fmt,pageno);
- }
- else
- sprintf(footer,"\n\n%ld\n",pageno);
-
- return(footer);
- }
-
- /*
- * seek given file pointer `numlines' lines towards the end of file
- */
-
- void skip_lines(fp, numlines)
- FILE *fp;
- long numlines;
- { if(numlines > 0)
- { while((fgetc(fp)!=LF) && !feof(fp))
- ;
- if(!feof(fp))
- skip_lines(fp, numlines-1);
- }
- }
-
- /*
- * Here we do the post-processing (column merging)
- */
-
- int join_columns(jobparm)
- struct jobparm *jobparm;
- { FILE *fp1, /* file pointer reading first column */
- *fp2, /* file pointer reading second column */
- *fpo; /* file pointer writing data */
- char *buf; /* line buffer */
-
- /* open files */
-
- if(!(fp1=fopen(TEMPNAME,"r")))
- { perror("File-Error: Unable to open `%s'.",TEMPNAME);
- return(STATE_ERRFILE);
- }
- if(!(fp2=fopen(TEMPNAME,"r")))
- { perror("Error: Unable to open `%s'.",TEMPNAME);
- if(fp1) fclose(fp1);
- return(STATE_ERRFILE);
- }
- { char *mode= (JP_APPEND(jobparm->flags)) ? ("a") : ("w");
- if(!(fpo= fopen(jobparm->outfile,mode)))
- { perror("File-Error: Unable to open %s.",jobparm->outfile);
- if(fp1) fclose(fp1);
- if(fp2) fclose(fp2);
- return(STATE_ERRPRT);
- }
- }
-
- /* allocate line buffer */
-
- if(!(buf=(char *)alloc_mem(jobparm->charct)))
- { perror("Fatal-Error: Unable to allocate %ld bytes of memory.",
- jobparm->charct);
- if(fp1) fclose(fp1);
- if(fp2) fclose(fp2);
- if(fpo) fclose(fpo);
- return(STATE_NOMEM);
- }
-
- skip_lines(fp2, jobparm->linect);
- term_clear;
-
- if(!feof(fp2))
- { char fmt[20];
- char *s,
- *header=NULL,
- *footer=NULL;
- long l=0,
- p=jobparm->firstpage;
-
- int linect= jobparm->linect;
-
- if(JP_HEADING(jobparm->flags))
- { linect-= HEADERLINES;
- header= make_heading(jobparm);
- fwrite(header, sizeof(char), strlen(header), fpo);
- }
-
- if(JP_FOOTING(jobparm->flags))
- { linect-= FOOTERLINES;
- footer= make_footing(jobparm,p);
- }
- sprintf(fmt,"%%-%lds | ",jobparm->charct/jobparm->columns);
-
- while(!(feof(fp1) || feof(fp2)))
- { for(s=buf;((*s=fgetc(fp1))!=LF) && !feof(fp1); s++)
- ;
- *s='\0';
- fprintf(fpo,fmt,buf);
- for(s=buf;((*s=fgetc(fp2))!=LF) && !feof(fp2); s++)
- ;
- *++s='\0';
- if(!feof(fp2))
- { fputs(buf,fpo);
- l++;
- if((l%linect)==0)
- { skip_lines(fp1, jobparm->linect);
- skip_lines(fp2, jobparm->linect);
- term_write(l);
- if(footer)
- { fwrite(footer,sizeof(char),strlen(footer),fpo);
- footer= make_footing(jobparm, ++p);
- }
- if(header) fwrite(header,sizeof(char),strlen(header),fpo);
- }
- }
- }
- }
- free_mem(buf);
- if(fp2) fclose(fp2);
- if(fp1) fclose(fp1);
- if(fpo) fclose(fpo);
- return(STATE_OKAY);
- }
-
- /*
- * print a file
- */
-
- int print_file(jobparm,jobstate)
- struct jobparm *jobparm;
- struct jobstate *jobstate;
- { static unsigned long pageno=1;
-
- FILE *fpi, /* input stream */
- *fpo; /* output stream */
-
- char *buf; /* line buffer */
- long b=0, /* general counter */
- inln=0, /* lines of input */
- outln=0, /* lines of output */
- wraps=0, /* #of word wraps */
- cracks=0, /* #of line breaks */
- cleanups=0, /* #of invisible chars */
- fillups=0; /* #of empty lines added */
-
- int indent = jobparm->indent,
- charct = jobparm->charct,
- linect = jobparm->linect,
- tabsize= jobparm->tabsize,
- flags = jobparm->flags;
-
- char *header= (char *)NULL; /* page header */
-
- /* open input- and output stream */
-
- if(jobparm->infile && *(jobparm->infile))
- { if(!(fpi=fopen(jobparm->infile,"r")))
- { perror("Error: Unable to open `%s'.\n",jobparm->infile);
- return(STATE_ERRFILE);
- }
- if(jobparm->columns > 1)
- { if(!(fpo= fopen(TEMPNAME, "w")))
- { perror("Error: Unable to write temorary data to %s.\n",TEMPNAME);
- if(fpi) fclose(fpi);
- return(STATE_ERRPRT);
- }
- charct /= jobparm->columns;
- if(JP_HEADING(flags))
- { linect-= (HEADERLINES * (jobparm->columns -1) );
- flags&= ~JPFLAG_HEADING;
- }
- if(JP_FOOTING(flags))
- { linect-= (FOOTERLINES * (jobparm->columns -1) );
- flags&= ~JPFLAG_FOOTING;
- }
- }
- else
- { char *mode= (JP_APPEND(flags)) ? ("a") : ("w");
- if(!(fpo= fopen(jobparm->outfile,mode)))
- { perror("Error: Unable to open %s.\n",jobparm->outfile);
- if(fpi) fclose(fpi);
- return(STATE_ERRPRT);
- }
- }
- }
- else return(STATE_ERRFILE); /* nothing to print */
-
- /* init printer */
-
- if(JP_MINI(flags))
- fprintf(fpo,INITMINI); /* begin with superscript */
- else if(!JP_PLAIN(flags))
- { if(dltype(ENV_VOLUME)!=DLT_UNKNOWN) /* env: exists */
- { FILE *fpx=fopen(INITPRINTER,"r");
- if(fpx)
- { char c;
- printf("%s found, printer installed.\n",INITPRINTER);
- while((c=fgetc(fpx))!=EOF && !feof(fpx))
- { fputc(c,fpo);
- if(c=='\n')
- outln++;
- }
- fclose(fpx);
- }
- }
- }
-
- if(!(buf=(char *)alloc_mem(charct)))
- { perror("Fatal-Error: Unable to allocate %ld bytes of memory.",
- charct);
- if(fpi) fclose(fpi);
- if(fpo) fclose(fpo);
- return(STATE_NOMEM);
- }
- for(b=0;b<indent;b++) /* init indention */
- buf[b]=' ';
- if(jobparm->leader)
- { strcpy(&buf[indent],jobparm->leader);
- indent+=strlen(jobparm->leader);
- }
- b= indent;
-
- printf(" %s => %s\r",jobparm->infile,jobparm->outfile);
-
- /* skip lines */
-
- if(jobparm->lineskip>0)
- { int skip= jobparm->lineskip;
- if(skip<0)
- skip= -skip*linect; /* skip pages */
- if(skip>0)
- skip_lines(fpi,skip);
- }
-
- if(jobparm->firstpage != 0)
- pageno= jobparm->firstpage;
- else jobparm->firstpage= pageno;
-
- if(JP_HEADING(flags))
- { header= make_heading(jobparm);
- linect-= HEADERLINES;
- }
- if(JP_FOOTING(flags))
- linect-= FOOTERLINES;
-
- /* main loop */
-
- { BOOL pbrk, lbrk; /* page break, line break read */
- char *rbuf;
- int refresh=(linect>1)?(linect):(DEFREFRESH);
- /* when to print out the current line number */
-
- while(!feof(fpi))
- { rbuf=&buf[b]; /* b==indent */
- do
- { *rbuf=fgetc(fpi);
- if(*rbuf==TAB && tabsize>0)
- { do
- { *rbuf++=' ';
- b++;
- }
- while((b%tabsize) && b<charct);
- lbrk=pbrk=FALSE;
- }
- else
- { lbrk=(*rbuf==LF);
- pbrk=(*rbuf==FF);
- b++;
- rbuf++;
- }
- } while(b<charct && !(pbrk || lbrk || feof(fpi)));
-
- rbuf--; /* set to the character read last
- * b = #of chars in buf[]
- */
-
- if(lbrk)
- { inln++; /* we've read a complete line */
- if(inln%refresh==0)
- term_write(inln); /* we're alive ! */
- }
-
- if(b<charct || lbrk || pbrk || feof(fpi) )
- { --rbuf; /* => don't write the character read last */
- --b;
- }
-
- if(JP_CLEANUP(flags)) /* => remove invisible chars */
- { while((*rbuf==' '||*rbuf=='\t') && b>0)
- { --rbuf;
- --b;
- cleanups++;
- }
- }
-
- if(header && (outln%linect)==0)
- fwrite(header, sizeof(char), strlen(header), fpo);
-
- if(b<charct) /* => normal line */
- { if((feof(fpi) && b>indent) || (!feof(fpi) && b>0))
- fwrite(buf,sizeof(char),b,fpo);
- newline(fpo,flags);
- outln++;
- /*
- * We increase outln in any case, since the first line on a new
- * page terminated without '\n' would imply (outln%linect) to
- * be ==0 and this page would NOT be filled up if an EOF follows.
- * note that a file ending without a '\n' character will get it from
- * lp in any case.
- */
- b=indent;
- }
- else /* line too long */
- { int bp=b-1; /* break,wrap position */
-
- /* search for a word wrap position */
- while(buf[bp]!=' ' && buf[bp]!='\t' && --bp>indent);
-
- if(bp>indent) /* => confirm word wrap */
- { int i;
- fwrite(buf,sizeof(char),bp,fpo);
- newline(fpo,flags);
- outln++;
- bp++; /* skip word terminating character */
- for(i=0;i<b-bp;i++) buf[indent+i]=buf[bp+i];
- b=indent+i;
- wraps++;
- }
-
- else /* => break line... we've got no choice */
- { fwrite(buf,sizeof(char),b,fpo);
- newline(fpo,flags);
- outln++;
- b=indent;
- cracks++;
- }
- }
-
- /* handle form feed character */
- if(pbrk && (outln%linect) > 0)
- { int al= linect-(outln%linect); /* #of additional lines */
- /* Warning:
- * If (outln%lincet)==0 we would add another lincet lines to
- * the output without increasing/printing the page number and a
- * new header! So: If a header and/or footer were also toggled,
- * linect would not be enough to fill up a full page since we
- * decreased it by headerlines and/or footerlines!!!
- */
- if(JP_USEFF(flags))
- fputc(FF, fpo);
- else
- { int i;
- for(i=0;i<al;i++) newline(fpo,flags);
- fillups+=al;
- }
- outln+=al;
-
- }
-
- if((outln%linect)==0)
- { if(JP_FOOTING(flags))
- { char *s= make_footing(jobparm, pageno);
- fwrite(s,sizeof(char),strlen(s),fpo);
- }
- pageno++;
- }
- }
- if(JP_FEEDOUT(flags))
- { linect*= jobparm->columns;
- for(b=0;(outln%linect)!=0;outln++,b++)
- newline(fpo,flags); /* feed out last page */
- fillups+=b;
-
- /* take care: (here was a bug v1.16)
- * if(b==0) we've already added the footer ! */
- if(b>0)
- { if(JP_FOOTING(flags))
- { char *s= make_footing(jobparm, pageno);
- fwrite(s,sizeof(char),strlen(s),fpo);
- }
- pageno++;
- }
- }
- }
- if(JP_MINI(flags))
- fprintf(fpo, INITNOMINI); /* turn off all special modi at the EOF */
-
- if(buf) free_mem(buf);
-
- if(fpi) fclose(fpi);
- if(fpo) fclose(fpo);
-
- jobstate->inln = inln;
- jobstate->outln = outln;
- jobstate->wraps = wraps;
- jobstate->cracks = cracks;
- jobstate->cleanups = cleanups;
- jobstate->fillups = fillups;
-
- if(jobparm->columns>1)
- join_columns(jobparm);
-
- return(STATE_OKAY);
- }
-
- /* write the statistics into our logfile */
-
- void statistics(struct jobparm *jp,
- struct jobstate *js )
- { FILE *sf;
- sf=fopen(LOGFILENAME,"a");
- if(sf)
- { long flags= jp->flags;
-
- fprintf(sf,"%s (%d+%d lines, %d cleaned, %d wraped, %d broken)\n",
- jp->infile,
- js->inln,
- js->fillups,
- js->cleanups,
- js->wraps,
- js->cracks );
-
- fprintf(sf,"jobparm -i%d -w%d -h%d -t%d -c%d ",jp->indent,
- jp->charct,
- jp->linect,
- jp->tabsize,
- jp->columns );
-
- if(JP_PLAIN(flags)) fprintf(sf,"-p "); else fprintf(sf,"+p ");
- if(JP_AUTOLF(flags)) fprintf(sf,"-e "); else fprintf(sf,"+e ");
- if(JP_MINI(flags)) fprintf(sf,"-m "); else fprintf(sf,"+m ");
- if(JP_USEFF(flags)) fprintf(sf,"-f "); else fprintf(sf,"+f ");
- if(JP_CLEANUP(flags)) fprintf(sf,"+d "); else fprintf(sf,"-d ");
- if(jp->leader) fprintf(sf,"-l \"%s\" ",jp->leader);
- if(jp->lineskip > 0) fprintf(sf,"-s %d ",jp->lineskip);
- else if(jp->lineskip < 0) fprintf(sf,"-n %d ",-(jp->lineskip));
- if(JP_REPLACE(flags)) fprintf(sf,"-r ");
- if(JP_APPEND(flags)) fprintf(sf,"-a "); else fprintf(sf,"+a ");
- if(jp->outfile) fprintf(sf,"-o \"%s\" ",jp->outfile);
- if(JP_HEADING(flags)) fprintf(sf,"-n "); else fprintf(sf,"+n ");
- if(JP_FEEDOUT(flags)) fprintf(sf,"-x "); else fprintf(sf,"+x ");
- if(JP_DOUBLESIDED(flags)) fprintf(sf,"-2 %d ",jp->firstpage);
- if(JP_SINGLESIDED(flags)) fprintf(sf,"-1 %d ",jp->firstpage);
- if(!JP_FOOTING(flags)) fprintf(sf,"+0 ");
- fprintf(sf,"\n\n");
- fclose(sf);
- }
- }
-
- /*
- * submit all print jobs in given jobparm list
- */
-
- int submit_printjob(jobparm)
- struct jobparm *jobparm;
- { int state= STATE_OKAY;
- struct jobstate jobstate;
-
- if(jobparm)
- { if(jobparm->infile && *(jobparm->infile) &&
- jobparm->outfile && *(jobparm->outfile) )
- { state= print_file(jobparm, &jobstate);
- if(state==STATE_OKAY)
- { if(JP_REPLACE(jobparm->flags))
- { DeleteFile(jobparm->infile);
- Rename(jobparm->outfile,jobparm->infile);
- }
- printf(" %s => %s [printed]\n",jobparm->infile, jobparm->outfile);
- statistics(jobparm, &jobstate);
- }
- }
- if(state==STATE_OKAY && jobparm->next)
- state= submit_printjob(jobparm->next);
- }
- return(state);
- }
-
- /*
- * here we build the whole jobparm-list out of main()'s arguments
- */
-
- struct jobparm *build_joblist(int argc, char *argv[])
- { struct jobparm *mainjob; /* head of the jobparm-list */
- int state= STATE_OKAY;
- mainjob= alloc_jobparm(NULL);
- if(mainjob)
- { struct jobparm *jobparm= mainjob; /* working pointer */
- jobparm= tail(jobparm);
- jobparm->next= alloc_jobparm(jobparm);
- jobparm= jobparm->next;
- if(jobparm)
- { arglist2jobparm(jobparm, argc, argv);
- check_jobparm(jobparm,0,"command-line");
- if(jobparm->tocfile)
- state= file2jobparm(jobparm, jobparm->tocfile);
- }
- else
- { perror("Not enough memory to parse command line!");
- state= STATE_NOMEM;
- }
- }
- else
- { perror("Not enough memory to allocate print job!");
- state= STATE_NOMEM;
- }
-
- if((state!=STATE_OKAY) && mainjob)
- { free_jobparm(mainjob);
- mainjob= (struct jobparm *)NULL;
- }
-
- return(mainjob);
- }
-
- void main(int argc, char *argv[])
- { int state; /* job state after execution attempt */
- struct jobparm *jobparm;
- onbreak(_abort); /* this is DICE */
-
- puts(BANNER); /* let me introduce myself... */
- if(argc==2 && (argv[1][0]=='?' || argv[1][0]=='.'))
- { char **s= howtouse;
- puts(USAGE);
- puts("\nLegal options are:\n");
- if(argv[1][0]=='?') while(*s)
- { printf("%-11s %s %s\n",s[0],s[2],s[3]);
- s= &s[4];
- }
- else while(*s)
- { printf("%-2s %s %s\n",s[1],s[2],s[3]);
- s= &s[4];
- }
- puts("\nALL THIS IS HIGHLY EXPERIMENTAL !!! TAKE GREAT CARE !!!");
- exit(0);
- }
-
- whoami=argv[0]; /* who am I ? */
- argc--;
- argv++; /* skip our name */
-
- jobparm= build_joblist(argc, argv);
- if(jobparm)
- { DeleteFile(LOGFILENAME);
- state= submit_printjob(jobparm);
- }
- free_jobparm(jobparm);
- exit((state==STATE_OKAY)?(0):(1));
- }
-