home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of A1200
/
World_Of_A1200.iso
/
programs
/
printer
/
lp
/
source.lha
/
source
/
lp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-11
|
41KB
|
1,386 lines
/* 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));
}