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

  1. /* ts=2;
  2. **  $RCSfile: lp.c,v $
  3. **  $Release$
  4. **  $Revision: 1.18 $
  5. **  $Date: 93/01/18 01:27:15 $
  6. **  $Author: tf $
  7. **
  8. **  (c) Copyright 1991,92 Tobias Ferber, All Rights Reserved.
  9. */
  10.  
  11. #include <exec/types.h>
  12. #include <stdio.h>
  13. #include <exec/memory.h>
  14.  
  15. /* instead of "memblock.h" */
  16.  
  17. extern char *alloc_mem(long);
  18. extern void free_mem(char *);
  19. extern void free_all(void);
  20.  
  21. char *whoami;  /* who am I? (copy of argv[0]) */
  22.  
  23. #include <stdarg.h>
  24.  
  25. void perror(const char *fmt, ...)
  26. {
  27.   va_list argp;
  28.   va_start(argp,fmt); /* name the last known argument */
  29.   fprintf(stdout,"\r%s: ",whoami);
  30.   vfprintf(stdout,fmt,argp);
  31.   fprintf(stdout,"\n");
  32.   fflush(stdout);
  33.   va_end(argp); /* just to be sure... */
  34. }
  35.  
  36. void _abort(void)
  37. { printf("^C\n\n***BREAK\n");
  38.   free_all();
  39.   exit(1);
  40. }
  41.  
  42. #include "strfn.h"
  43.  
  44. static char rcs_id[] = "$VER: $Id: lp.c,v 1.18 93/01/18 01:27:15 tf Exp $";
  45.  
  46. #define BANNER &rcs_id[6]
  47.  
  48. struct jobparm
  49. { int indent;       /* left margin */
  50.   int charct;       /* characters per line = bufsize */
  51.   int linect;       /* #of lines per page */
  52.   int tabsize;      /* 0 = don't convert tabs -> spaces */
  53.   int columns;      /* #of columns: width= charct/columns */
  54.   long flags;       /* see JPFLAG_XXXX */
  55.   char *leader;     /* output line leader */
  56.   int firstpage;    /* pageno to start numbering with */
  57.   int lineskip;     /* number of lines to be skiped at tof */
  58.   char *infile;     /* input filename */
  59.   char *outfile;    /* output filename */
  60.   char *tocfile;    /* list file filename (table of contents) */
  61.   char *argmem;     /* argument buffer */
  62.   long membytes;    /* size of allocated argument buffer */
  63.   struct jobparm *next; /* next job to submit */
  64. };
  65.  
  66. #define JPFLAG_APPEND       (1L)      /* append output to print destination */
  67. #define JPFLAG_REPLACE      (1L<<1)   /* replace input file by output file */
  68. #define JPFLAG_PLAIN        (1L<<2)   /* don't ENV:InitPrinter */
  69. #define JPFLAG_AUTOLF       (1L<<3)   /* send CR, no LF for new lines */
  70. #define JPFLAG_MINI         (1L<<4)   /* print superscript, subscript... */
  71. #define JPFLAG_USEFF        (1L<<5)   /* send FF, not a sequence of LF */
  72. #define JPFLAG_CLEANUP      (1L<<6)   /* delete SPC/TAB at the end of a line */
  73. #define JPFLAG_HEADING      (1L<<7)   /* print a page header */
  74. #define JPFLAG_FOOTING      (1L<<8)   /* print page footings */
  75. #define JPFLAG_DOUBLESIDED  (1L<<9)   /* flag for type of page numbering */
  76. #define JPFLAG_FEEDOUT      (1L<<10)  /* feed out the last sheet of a file */
  77.  
  78. #define JP_APPEND(f)        (((f)&JPFLAG_APPEND)==JPFLAG_APPEND)
  79. #define JP_REPLACE(f)       (((f)&JPFLAG_REPLACE)==JPFLAG_REPLACE)
  80. #define JP_PLAIN(f)         (((f)&JPFLAG_PLAIN)==JPFLAG_PLAIN)
  81. #define JP_AUTOLF(f)        (((f)&JPFLAG_AUTOLF)==JPFLAG_AUTOLF)
  82. #define JP_MINI(f)          (((f)&JPFLAG_MINI)==JPFLAG_MINI)
  83. #define JP_USEFF(f)         (((f)&JPFLAG_USEFF)==JPFLAG_USEFF)
  84. #define JP_CLEANUP(f)       (((f)&JPFLAG_CLEANUP)==JPFLAG_CLEANUP)
  85. #define JP_HEADING(f)       (((f)&JPFLAG_HEADING)==JPFLAG_HEADING)
  86. #define JP_FOOTING(f)       (((f)&JPFLAG_FOOTING)==JPFLAG_FOOTING)
  87. #define JP_DOUBLESIDED(f)   (((f)&JPFLAG_DOUBLESIDED)==JPFLAG_DOUBLESIDED)
  88. #define JP_SINGLESIDED(f)   (!(JP_DOUBLESIDED(f)))
  89. #define JP_FEEDOUT(f)       (((f)&JPFLAG_FEEDOUT)==JPFLAG_FEEDOUT)
  90.  
  91. /*
  92.  * \a = $07 [BELL]
  93.  * \b = $08 [BACKSPACE]
  94.  * \t = $09 [TAB]
  95.  * \n = $0a [LF]
  96.  * \v = $0b
  97.  * \f = $0c [FF]
  98.  * \r = $0d [CR]
  99.  * \x = $ff [EOF]
  100.  */
  101.  
  102. #define TAB '\t'
  103. #define LF  '\n'
  104. #define CR  '\r'
  105. #define FF  '\f'
  106.  
  107. #define SUPERSCRIPT "\15\33[2v"
  108. #define SUBSCRIPT   "\12\33[4v"
  109.  
  110. void newline(FILE *fp, long flags)
  111. { static BOOL ss=FALSE;  /* first newline changes to subscript */
  112.   if(JP_MINI(flags))
  113.   { fprintf(fp,(ss)?(SUPERSCRIPT):(SUBSCRIPT));
  114.     ss=!ss;
  115.   }
  116.   else if(JP_AUTOLF(flags))
  117.     fputc(CR,fp);
  118.   else
  119.     fputc(LF,fp);
  120. }
  121.  
  122. #define term_write(num)                   \
  123.         do                                \
  124.         { fprintf(stdout," %ld\r",num);   \
  125.           fflush(stdout);                 \
  126.         } while(0);
  127.  
  128. #define term_clear                        \
  129.         do                                \
  130.         { fprintf(stdout,"       \r");    \
  131.           fflush(stdout);                 \
  132.         } while(0);
  133.  
  134. #define ENV_VOLUME    "ENV:"
  135. #define ENV_LPOPTS    "ENV:LPOPTS"
  136. #define INITPRINTER   "ENV:InitPrinter"
  137. #define INITMINI      "\33c\33#4\33[2w\33[4w\33[0z\33[2v"
  138. #define INITNOMINI    "\33#1"   /* turn off all special modi */
  139. #define PRINTERNAME   "PRT:"
  140. #define LOGFILENAME   "lp.log"
  141. #define DEFOUT        "lp.out"
  142. #define TEMPNAME      "lp$col.tmp"
  143. #define USAGE         "USAGE: lp [options] [infile] [@tocfile]"
  144.  
  145. #define DEFCHARCT   80L
  146. #define DEFINDENT   0L
  147. #define DEFTABSIZE  8L
  148. #define DEFLINECT   66L
  149. #define DEFREFRESH  DEFLINECT
  150. #define DEFJPFLAGS  JPFLAG_CLEANUP
  151.  
  152.  
  153. static char *jobreport[]=   /* not used */
  154. { "Print job terminated without errors.",                     /* 0 */
  155.   "Fatal-Error: AllocMem() failed, ran out of memory.",       /* 1 */
  156.   "Nothing to print.",                                        /* 2 */
  157.   "Unable to open input file.",                               /* 3 */
  158.   "Error: Illegal or unknown directive.",                     /* 4 */
  159.   "Unable to open print destination.",                        /* 5 */
  160.   "Fatal-Error: source of error unknown.",                    /* 6 */
  161. };
  162.  
  163. #define STATE_OKAY    0L
  164. #define STATE_NOMEM   1L
  165. #define STATE_NOFILE  2L
  166. #define STATE_ERRFILE 3L
  167. #define STATE_ERROPT  4L
  168. #define STATE_ERRPRT  5L
  169. #define STATE_FATAL   6L
  170.  
  171. struct jobstate
  172. { long inln;     /* lines of input */
  173.   long outln;    /* lines of output */
  174.   long wraps;    /* #of performed word wraps */
  175.   long cracks;   /* #of broken lines */
  176.   long cleanups; /* #of invisible chars removed */
  177.   long fillups;  /* #of empty lines added */
  178. };
  179.  
  180. char *alloc_argmem(jobparm,bytesize)
  181. struct jobparm *jobparm;
  182. long bytesize;
  183. { char *argmem;
  184.   argmem= (char *)alloc_mem(bytesize);
  185.   if(argmem)
  186.   { jobparm->argmem= argmem;
  187.     jobparm->membytes= bytesize;
  188.   }
  189.   return(argmem);
  190. }
  191.  
  192. char *load_argfile(jobparm,filename)
  193. struct jobparm *jobparm;
  194. char *filename;
  195. { FILE *fp;
  196.   char *argmem=(char *)NULL;
  197.   if(filename)
  198.   { long fsize=0;
  199.     fp=fopen(filename,"r");
  200.     if(fp)
  201.     { fseek(fp, 0L, 2L);  /* OFFSET_END = 2L */
  202.       fsize=ftell(fp);
  203.       if(fsize)
  204.       { fseek(fp, 0L, 0L);
  205.         argmem= alloc_argmem(jobparm, 1+fsize); /* + EOF */
  206.         if(argmem)
  207.         { fread(argmem, sizeof(char), fsize, fp);
  208.           argmem[fsize]= EOF;
  209.         }
  210.       }
  211.       fclose(fp);
  212.     }
  213.   }
  214.   return(argmem);
  215. }
  216.  
  217. /*
  218.  * Amiga options:   /S Switch
  219.  *                  /K Keyword
  220.  *                  /N Number
  221.  *                  /T Toggle
  222.  *                  /A Required
  223.  *                  /F Rest of line
  224.  *                  /M Multiple strings
  225.  *
  226.  * Note that there *MUST* be a space character following the option string!
  227.  */
  228.  
  229. static char *howtouse[] = {
  230.  
  231.   "INDENT",      "-i", "<indent> ", "set indention, left margin (default: 0)",
  232.   "WIDTH",       "-w", "<charct> ", "set page width, right margin (default: 80)",
  233.   "HEIGHT",      "-h", "<linect> ", "set page height in #of lines per page (default: 66)",
  234.   "FILE",        "-u", "<infile> ", "force next argument to be the input filename",
  235.   "TO",          "-o", "<outfile>", "set output device or file (default is PRT:)",
  236.   "APPEND",      "-a", "         ", "append output to print destination (default for @tocfiles)",
  237.   "NOAPPEND",    "+a", "         ", "overwrite print destination (default)",
  238.   "REPLACE",     "-r", "         ", "replace the input file by the output file",
  239.   "TABSIZE",     "-t", "[tabsize]", "set tabsize and convert tabs to spaces",
  240.   "USETAB",      "+t", "         ", "send tabs, don't convert tabs to spaces",
  241.   "CRONLY",      "-e", "         ", "print with AUTO CR/LF option (send CR only)",
  242.   "LFONLY",      "+e", "         ", "turn off AUTO CR/LF option (send normal LF)",
  243.   "USEFF",       "-f", "         ", "use formfeed (FF) characters for new pages",
  244.   "NOFF",        "+f", "         ", "convert a formfeed into a sequece of linefeeds (default)",
  245.   "PLAIN",       "-p", "         ", "print plain, don't (ENV:) init printer",
  246.   "NOPLAIN",     "+p", "         ", "add ENV:InitPrinter to the top of the file (default)",
  247.   "MINI",        "-m", "         ", "print one line superscript, next subscript...",
  248.   "NOMINI",      "+m", "         ", "turn off MINI option '-m' (default)",
  249.   "SKIPTOPAGE",  "-b", "<pageno> ", "begin printing with the first line of page <pageno>",
  250.   "SKIPTOLINE",  "-s", "<lineno> ", "start with line <lineno> of the input file (default: 1)",
  251.   "NOCLEANUP",   "-d", "         ", "don't delete spaces or tabs at the end of a line",
  252.   "CLEANUP",     "+d", "         ", "delete spaces or tabs at the end of a line (default)",
  253.   "LEADER",      "-l", "<string> ", "print <string> in front of each output line",
  254.   "NOLEADER",    "+l", "         ", "do not print any leading string",
  255.   "HEADER",      "-n", "         ", "print page header (filename, date)",
  256.   "NOHEADER",    "+n", "         ", "turn off HEADER option '-n', don't print any header (default)",
  257.   "SINGLESIDED", "-1", "[pageno] ", "single sided page numbering beginning with page [pageno]",
  258.   "DOUBLESIDED", "-2", "[pageno] ", "page numbering for double sided output.",
  259.   "NOFOOTINGS",  "+0", "         ", "no page numbering, no footings (default)",
  260.   "COLUMNS",     "-c", "<columns>", "set #of columns of equal width (default: 1, max: 2)",
  261.   "FEEDOUT",     "-x", "         ", "expand each file via LF to fill up its last sheet",
  262.   "NOFEEDOUT",   "+x", "         ", "do not add anything to the end of file (default)",
  263.   "WITH",        "@",  "<tocfile>", "print a list of files (each with it's arguments)",
  264.   NULL, NULL, NULL, NULL
  265. };
  266.  
  267. /*
  268.  * arglist2jobparm() parses argc arguments of given arglist argv[]
  269.  * and fills the jobparm structure accordingly. (no checking!)
  270.  */
  271.  
  272. void arglist2jobparm(jobparm, argc, argv)
  273. struct jobparm *jobparm;
  274. int argc;
  275. char *argv[];
  276. { char *arg;
  277.   if(jobparm)
  278.   { while(argc>0)
  279.     { arg=argv[0];
  280.  
  281.       if(isalpha(*arg))
  282.       { char **aopt= &howtouse[0];
  283.         /*while(*aopt && strnicmp(arg,*aopt,strlen(*aopt)))*/
  284.         while(*aopt && stricmp(arg,*aopt))
  285.           aopt= &aopt[4];
  286.         if(*aopt) arg= aopt[1];
  287.         /*if(*aopt) printf("AmigaDOS option %s changed to '%s'\n",aopt[0],aopt[1]);*/
  288.       }
  289.  
  290.       if(*arg=='-')
  291.       { arg++;
  292.         switch(*arg)
  293.         {
  294. /* -1 */  case '1':
  295.             if(arg[1]) jobparm->firstpage= atol(arg+1);
  296.             else if('0'<=argv[1][0] && argv[1][0]<='9') /* isdigit(n) ? */
  297.             { argv++;
  298.               argc--;
  299.               jobparm->firstpage= atol(argv[0]);
  300.             }
  301.             jobparm->flags |= JPFLAG_FOOTING;
  302.             jobparm->flags &= ~JPFLAG_DOUBLESIDED;
  303.             break;
  304. /* -2 */  case '2':
  305.             if(arg[1]) jobparm->firstpage= atol(arg+1);
  306.             else if('0'<=argv[1][0] && argv[1][0]<='9') /* isdigit(n) ? */
  307.             { argv++;
  308.               argc--;
  309.               jobparm->firstpage= atol(argv[0]);
  310.             }
  311.             jobparm->flags |= JPFLAG_FOOTING;
  312.             jobparm->flags |= JPFLAG_DOUBLESIDED;
  313.             break;
  314. /* -a */  case 'a': case 'A':
  315.             jobparm->flags |= JPFLAG_APPEND;
  316.             break;
  317. /* -b */  case 'b': case 'B':
  318.             if(arg[1]) jobparm->lineskip= -atol(arg+1);
  319.             else
  320.             { argv++;
  321.               argc--;
  322.               jobparm->lineskip= -atol(argv[0]);
  323.             }
  324.             break;  /* negative lineskip will be converted to pageskip later */
  325. /* -c */  case 'c': case 'C':
  326.             if(arg[1]) jobparm->columns= atol(arg+1);
  327.             else
  328.             { argv++;
  329.               argc--;
  330.               jobparm->columns= atol(argv[0]);
  331.             }
  332.             break;
  333. /* -d */  case 'd': case 'D':
  334.             jobparm->flags &= ~JPFLAG_CLEANUP;
  335.             break;
  336. /* -e */  case 'e': case 'E':
  337.             jobparm->flags |= JPFLAG_AUTOLF;
  338.             break;
  339. /* -f */  case 'f': case 'F':
  340.             jobparm->flags |= JPFLAG_USEFF;
  341.             break;
  342. /* -h */  case 'h': case 'H':
  343.             if(arg[1]) jobparm->linect= atol(arg+1);
  344.             else
  345.             { argv++;
  346.               argc--;
  347.               jobparm->linect= atol(argv[0]);
  348.             }
  349.             break;
  350. /* -i */  case 'i': case 'I':
  351.             if(arg[1]) jobparm->indent= atol(arg+1);
  352.             else
  353.             { argv++;
  354.               argc--;
  355.               jobparm->indent= atol(argv[0]);
  356.             }
  357.             break;
  358.  
  359. /* -l */  case 'l': case 'L':
  360.             if(arg[1]) jobparm->leader= &arg[1];
  361.             else
  362.             { argv++;
  363.               argc--;
  364.               jobparm->leader= argv[0];
  365.             }
  366.             break;
  367. /* -m */  case 'm': case 'M':
  368.             jobparm->flags |= JPFLAG_MINI;
  369.             break;
  370. /* -n */  case 'n': case 'N':
  371.             jobparm->flags |= JPFLAG_HEADING;
  372.             break;
  373. /* -o */  case 'o': case 'O':
  374.             if(arg[1]) jobparm->outfile= &arg[1];
  375.             else
  376.             { argv++;
  377.               argc--;
  378.               jobparm->outfile= argv[0];
  379.             }
  380.             break;
  381. /* -p */  case 'p': case 'P':
  382.             jobparm->flags |= JPFLAG_PLAIN;
  383.             break;
  384. /* -r */  case 'r': case 'R':
  385.             jobparm->outfile= DEFOUT;
  386.             jobparm->flags &= ~JPFLAG_APPEND;
  387.             jobparm->flags |= JPFLAG_REPLACE;
  388.             break;
  389. /* -s */  case 's': case 'S':
  390.             if(arg[1]) jobparm->lineskip= atol(arg+1);
  391.             else
  392.             { argv++;
  393.               argc--;
  394.               jobparm->lineskip= atol(argv[0]);
  395.             }
  396.             break;
  397. /* -t */  case 't': case 'T':
  398.             if(arg[1]) jobparm->tabsize= atol(arg+1);
  399.             else if('0'<=argv[1][0] && argv[1][0]<='9') /* isdigit(n) ? */
  400.             { argv++;
  401.               argc--;
  402.               jobparm->tabsize= atol(argv[0]);
  403.             }
  404.             else jobparm->tabsize= DEFTABSIZE;
  405.             break;
  406. /* -u */  case 'u': case 'U':
  407.             if(arg[1]) jobparm->infile= &arg[1];
  408.             else
  409.             { argv++;
  410.               argc--;
  411.               jobparm->infile= argv[0];
  412.             }
  413.             break;
  414. /* -w */  case 'w': case 'W':
  415.             if(arg[1]) jobparm->charct= atol(arg+1);
  416.             else
  417.             { argv++;
  418.               argc--;
  419.               jobparm->charct= atol(argv[0]);
  420.             }
  421.             break;
  422. /* -x */  case 'x': case 'X':
  423.             jobparm->flags |= JPFLAG_FEEDOUT;
  424.             break;
  425.           default:
  426.             perror("Warning: Unknown option `-%c' ignored.",*arg);
  427.         }
  428.       }
  429.       else if(*arg=='+')
  430.       { arg++;
  431.         switch(*arg)
  432.         {
  433. /* +0 */  case '0':
  434.             jobparm->flags &= ~JPFLAG_FOOTING;
  435.             break;
  436. /* +a */  case 'a': case 'A':
  437.             jobparm->flags &= ~JPFLAG_APPEND;
  438. /* +d */  case 'd': case 'D':
  439.             jobparm->flags |= JPFLAG_CLEANUP;
  440.             break;
  441. /* +e */  case 'e': case 'E':
  442.             jobparm->flags &= ~JPFLAG_AUTOLF;
  443.             break;
  444. /* +f */  case 'f': case 'F':
  445.             jobparm->flags &= ~JPFLAG_USEFF;
  446.             break;
  447. /* +l */  case 'l': case 'L':
  448.             jobparm->leader = (char *)NULL;
  449.             break;
  450. /* +m */  case 'm': case 'M':
  451.             jobparm->flags &= ~JPFLAG_MINI;
  452.             break;
  453. /* +n */  case 'n': case 'N':
  454.             jobparm->flags &= ~JPFLAG_HEADING;
  455.             break;
  456. /* +p */  case 'p': case 'P':
  457.             jobparm->flags &= ~JPFLAG_PLAIN;
  458.             break;
  459. /* +t */  case 't': case 'T':
  460.             jobparm->tabsize= 0;
  461.             break;
  462. /* +x */  case 'x': case 'X':
  463.             jobparm->flags &= ~JPFLAG_FEEDOUT;
  464.             break;
  465.           default:
  466.             perror("Warning: Unknown option '+%c' ignored.",*arg);
  467.         }
  468.       }
  469.       else if(*arg=='@')
  470.       { if(arg[1])
  471.           jobparm->tocfile= &arg[1];
  472.         else
  473.         { argv++;
  474.           argc--;
  475.           jobparm->tocfile= argv[0];
  476.         }
  477.         jobparm->flags |= JPFLAG_APPEND;
  478.       }
  479.       else if(*arg > ' ')
  480.         jobparm->infile= arg;
  481.       argc--;
  482.       argv++;
  483.     }
  484.   }
  485. }
  486.  
  487. #define MAXARGS 50   /* maximum #of arguments per line */
  488.  
  489. /*
  490.  * make_arglist() converts given argument string `args' into a list of argv[]
  491.  * and a #of args `argc'.
  492.  */
  493.  
  494. char *make_arglist(args, argc, argv, line)
  495. char *args;
  496. int *argc;
  497. char *argv[];
  498. long *line;
  499. { int ac=0,         /* argument counter */
  500.       smode=0;      /* scanner mode:  0= outer arg mode
  501.                      *                1= inner argument mode
  502.                      *                2= inner quote mode
  503.                      *                3= EOL found
  504.                      *                4= EOF reached
  505.                      */
  506.   char *t=args;     /* pointer to the beginning of the current arg string */
  507.  
  508.   while(smode<3)
  509.   {
  510.     switch(*args)
  511.     {  case ';':
  512.         if(smode<2)
  513.         { *args='\0';
  514.           while(*args!='\n' && *args!=EOF)   /* ';' == EOL comment leader */
  515.             args++;
  516.         }
  517.         else ++args;
  518.         break;
  519.       case '\n': case EOF:
  520.         (*line)++; /* since our caller begins counting with line=0 */
  521.         if(smode==2)
  522.         { perror("Warning: Unmatched quote found.");
  523.           ac= -1;     /* error! */
  524.           *args= EOF; /* stop scanner (return NULL) */
  525.         }
  526.         else if(smode==1)
  527.           argv[ac++]=t;
  528.         if(*args==EOF) smode=4;
  529.         else
  530.         { if(ac>0) smode=3;
  531.         }
  532.         *args++='\0';
  533.         t=args;
  534.         break;
  535.       case '\"':
  536.         if(smode>0)
  537.         { argv[ac++]=t;
  538.           *args='\0';
  539.           if(smode==1) smode=2;
  540.           else smode=0;
  541.         }
  542.         else smode=2;
  543.         t=++args;
  544.         break;
  545.       case ' ': case '\t':
  546.         if(smode<2)
  547.         { if(smode==1)
  548.           { argv[ac++]=t;
  549.             *args='\0';
  550.           }
  551.           t=&args[1];
  552.           smode=0;
  553.         }
  554.         ++args;
  555.         break;
  556.       default:
  557.         if(smode==0) smode=1;
  558.         ++args;
  559.         break;
  560.     }
  561.   }
  562.  
  563.   *argc=ac;
  564.   return (smode==4) ? (char *)NULL : args;
  565. }
  566.  
  567. /*
  568.  * check the settings in a jobparm structure
  569.  */
  570.  
  571. int check_jobparm(jobparm, line, from)
  572. struct jobparm *jobparm;
  573. int line;
  574. char *from;
  575. { int state= STATE_OKAY;
  576.   char loc[256];  /* error location */
  577.  
  578.   if(line>0)
  579.     sprintf(loc,"Error line %ld \"%s\"",line,from);
  580.   else
  581.     sprintf(loc,"Error in %s",from);
  582.  
  583.   if(jobparm->charct<1)
  584.   { perror("%s Illegal page width %ld  (option -w).",
  585.       loc,jobparm->charct );
  586.     state= STATE_ERROPT;
  587.   }
  588.   if(jobparm->linect<1)
  589.   { perror("%s Illegal page height %d  (option -h).",
  590.       loc,jobparm->linect );
  591.     state= STATE_ERROPT;
  592.   }
  593.   if(jobparm->indent<0)
  594.   { perror("%s Negative indention (%ld) not supported.",
  595.       loc,jobparm->indent );
  596.     state= STATE_ERROPT;
  597.   }
  598.   if(jobparm->charct <= jobparm->indent)
  599.   { perror("%s Page width must be > indention!",loc);
  600.     state= STATE_ERROPT;
  601.   }
  602.   if(!(jobparm->outfile && *(jobparm->outfile)))
  603.   { perror("%s No output (device) specified.",loc);
  604.     state= STATE_ERRPRT;
  605.   }
  606.   return(state);
  607. }
  608.  
  609. /*
  610.  * tail() returns a pointer to the last jobparm structure in the job-list
  611.  * using a while loop instead of recursion to increase efficiency.
  612.  */
  613.  
  614. struct jobparm *tail(node)
  615. struct jobparm *node;
  616. { while(node->next)
  617.     node= node->next;
  618.   return(node);
  619. }
  620.  
  621. /*
  622.  * file2jobparm() converts each line of given file(name) into a jobparm
  623.  * structure and chains the jobparm structures to a list.
  624.  * The head of this chained list (i.e. first line's jobparm structure)
  625.  * will then be chained to the given jobparm structure.
  626.  *
  627.  * NOTE:
  628.  *   Given jobparm structure contains the default settings for the whole
  629.  * file.  Each new allocated jobparm structure will be initilalized with
  630.  * it's values.
  631.  */
  632.  
  633. struct jobparm *alloc_jobparm(); /* pre-declaration */
  634.  
  635. int file2jobparm(jp_base, filename)
  636. struct jobparm *jp_base;
  637. char *filename;
  638. {
  639.   static char *tgraph[256];  /* recursion depth limited to 256 !!! */
  640.   static int tnodect= 0;
  641.   int state= STATE_FATAL;
  642.  
  643.   if(jp_base && filename && *filename)
  644.   { char *filemem;
  645.  
  646.     /* Check the tgraph for non-deterministic recursions. */
  647.  
  648.     int n;
  649.     for(n=0; n<tnodect; n++)
  650.     { if(!stricmp(filename, tgraph[n]))
  651.       { perror("Fatal-Error with \"%s\"  Contents is non-deterministic!",
  652.           filename);
  653.         return(STATE_FATAL);
  654.       }
  655.     }
  656.     if(tnodect>=225)
  657.     { perror("Ran out of memory!  Recursion depth > 256");
  658.       return(STATE_FATAL);
  659.     }
  660.     tgraph[tnodect++]= filename; /* add the tgraph node */
  661.  
  662.     filemem= load_argfile(jp_base, filename);
  663.     if(filemem)
  664.     { struct jobparm *jobparm= jp_base; /* working pointer */
  665.       char *args=filemem;   /* pointer into filemem */
  666.       int argc;             /* argument counter */
  667.       char *argv[MAXARGS];  /* argument list */
  668.       long line=0;          /* line number for error messages */
  669.       state= STATE_OKAY;    /* everything seems okay now */
  670.  
  671.       while(args && (state==STATE_OKAY))
  672.       { jobparm->next= alloc_jobparm(jp_base);
  673.         if(jobparm->next)
  674.         { jobparm= jobparm->next;
  675.           args= make_arglist(args, &argc, argv, &line);
  676.           if(argc<0)
  677.           { perror("Error line %ld \"%s\"  Argument scan failed.",
  678.               line,filename);
  679.             return(STATE_FATAL);
  680.           }
  681.           arglist2jobparm(jobparm,argc,argv);
  682.           state= check_jobparm(jobparm, line, filename);
  683.           if(state==STATE_OKAY)
  684.           { if(jobparm->tocfile && *(jobparm->tocfile))
  685.             { 
  686.               /* prevent lp from performing non-deterministric recursions */
  687.               for(n=0; n<tnodect; n++)
  688.               { if(!stricmp(jobparm->tocfile, tgraph[n]))
  689.                 { perror("Fatal-Error line %ld \"%s\"  Non-deterministic recursion!",
  690.                     line,filename);
  691.                   return(STATE_FATAL);
  692.                 }
  693.               }
  694.               state= file2jobparm(jobparm, jobparm->tocfile);
  695.             }
  696.             jobparm= tail(jobparm);
  697.           }
  698.         }
  699.         else
  700.         { perror("Error line %ld \"%s\"  Out of memory!",
  701.             line,filename);
  702.           state=STATE_NOMEM;
  703.         }
  704.       }
  705.     }
  706.     else
  707.     { perror("File-Error: Unable to load \"%s\".",filename);
  708.       state=STATE_NOMEM;
  709.     }
  710.     --tnodect; /* delete the tgraph node */
  711.   }
  712.   return(state);
  713. }
  714.  
  715. void free_jobparm(struct jobparm *jobparm)
  716. { if(jobparm)
  717.   { if(jobparm->next)
  718.       free_jobparm(jobparm->next);
  719.     if(jobparm->argmem && jobparm->membytes)
  720.       free_mem(jobparm->argmem);
  721.     free_mem(jobparm);
  722.   }
  723. }
  724. /*
  725.  * allocate jobparm structure and init default values.
  726.  */
  727.  
  728. struct jobparm *alloc_jobparm(jp_default)
  729. struct jobparm *jp_default;
  730. { struct jobparm *jobparm;
  731.  
  732.   jobparm= (struct jobparm *)alloc_mem(sizeof(struct jobparm));
  733.   if(jobparm)
  734.   {
  735.     /* Just to be sure that this is unset: */
  736.  
  737.     jobparm->firstpage   = 0;             /* => continue with current # */
  738.     jobparm->infile      = (char *)NULL;  /* which file to print? */
  739.     jobparm->tocfile     = (char *)NULL;  /* list of files for this job */
  740.     jobparm->argmem      = (char *)NULL;  /* not allocated yet */
  741.     jobparm->membytes    = 0;             /* => not set yet */
  742.     jobparm->next        = (struct jobparm *)NULL;
  743.  
  744.     if(jp_default)
  745.     { jobparm->indent    = jp_default->indent;
  746.       jobparm->charct    = jp_default->charct;
  747.       jobparm->linect    = jp_default->linect;
  748.       jobparm->tabsize   = jp_default->tabsize;
  749.       jobparm->columns   = jp_default->columns;
  750.       jobparm->flags     = jp_default->flags;
  751.       jobparm->leader    = jp_default->leader;
  752.       jobparm->lineskip  = jp_default->lineskip;
  753.       jobparm->outfile   = jp_default->outfile;
  754.     }
  755.     else
  756.     { jobparm->indent    = DEFINDENT;    /* left margin */
  757.       jobparm->charct    = DEFCHARCT;    /* characters per line = bufsize */
  758.       jobparm->linect    = DEFLINECT;    /* = don't fill pages */
  759.       jobparm->tabsize   = 0;            /* = don't convert tabs -> spaces */
  760.       jobparm->columns   = 1;            /* #of columns of equal width */
  761.       jobparm->flags     = DEFJPFLAGS;   /* default flags */
  762.       jobparm->outfile   = PRINTERNAME;  /* should be "PRT:" */
  763.  
  764.       if((dltype(ENV_VOLUME)!=DLT_UNKNOWN) && fexist(ENV_LPOPTS))
  765.         file2jobparm(jobparm, ENV_LPOPTS);
  766.     }
  767.   }
  768.   return(jobparm);
  769. }
  770.  
  771. #define HEADERLINES 3L
  772.  
  773. /*
  774.  * make the headerlines and return a pointer to it's static string
  775.  */
  776.  
  777. #include <time.h>
  778.  
  779. char *make_heading(jobparm)
  780. struct jobparm *jobparm;
  781. { static char header[512];
  782.   int len, maxlen;
  783.  
  784.   /*len = stcgfn(header,jobparm->infile);*/
  785.                               /* seperate filename's node.ext */
  786.  
  787.   len= strlen(jobparm->infile);
  788.   strcpy(header,jobparm->infile);
  789.  
  790.   maxlen = jobparm->charct;
  791.  
  792.   if(len>maxlen && maxlen>3)
  793.     strcpy(&header[maxlen-3],"...");
  794.   else if(len+24< maxlen)
  795.   { long t;
  796.     char *s;
  797.     time(&t);        /* get #of sec. since 00:00:00 GMT Jan 1, 1970 */
  798.     s= ctime(&t);    /* convert to 26 characters ASCII string */
  799.     s[24]='\0';      /* remove '\n' character */
  800.     for(t=len; t<maxlen-24; t++)
  801.       header[t]=' ';
  802.     strcpy(&header[t],s);
  803.   }
  804.   else header[0]='\0';
  805.   strcat(header,"\n\n\n");
  806.   return(header);
  807. }
  808.  
  809. /*
  810.  * make the footer lines in the same way
  811.  */
  812.  
  813. int numdigits(unsigned long x)  /* get #of digits in a long */
  814. { int d=0;
  815.   do
  816.   { x/=10;
  817.     d++;
  818.   } while(x>0);
  819.   return(d);
  820. }
  821.  
  822. #define FOOTERLINES 3L
  823.  
  824. /*
  825.  * make page footings, return a pointer to a static string
  826.  */
  827.  
  828. char *make_footing(jobparm, pageno)
  829. struct jobparm *jobparm;
  830. unsigned long pageno;
  831. { static char footer[512];
  832.   char fmt[80];
  833.  
  834.   if(JP_SINGLESIDED(jobparm->flags))
  835.   { sprintf(fmt,"\n\n%%%ldld\n",
  836.       (jobparm->charct + numdigits(pageno) -1) /2 );
  837.     sprintf(footer,fmt,pageno);
  838.   }
  839.   else if(pageno%2)
  840.   { sprintf(fmt,"\n\n%%%ldld\n",jobparm->charct);
  841.     sprintf(footer,fmt,pageno);
  842.   }
  843.   else
  844.     sprintf(footer,"\n\n%ld\n",pageno);
  845.  
  846.   return(footer);
  847. }
  848.  
  849. /*
  850.  * seek given file pointer `numlines' lines towards the end of file
  851.  */
  852.  
  853. void skip_lines(fp, numlines)
  854. FILE *fp;
  855. long numlines;
  856. { if(numlines > 0)
  857.   { while((fgetc(fp)!=LF) && !feof(fp))
  858.       ;
  859.     if(!feof(fp))
  860.       skip_lines(fp, numlines-1);
  861.   }
  862. }
  863.  
  864. /*
  865.  * Here we do the post-processing (column merging)
  866.  */
  867.  
  868. int join_columns(jobparm)
  869. struct jobparm *jobparm;
  870. { FILE *fp1,    /* file pointer reading first column */
  871.        *fp2,    /* file pointer reading second column */
  872.        *fpo;    /* file pointer writing data */
  873.   char *buf;    /* line buffer */
  874.  
  875.   /* open files */
  876.  
  877.   if(!(fp1=fopen(TEMPNAME,"r")))
  878.   { perror("File-Error: Unable to open `%s'.",TEMPNAME);
  879.     return(STATE_ERRFILE);
  880.   }
  881.   if(!(fp2=fopen(TEMPNAME,"r")))
  882.   { perror("Error: Unable to open `%s'.",TEMPNAME);
  883.     if(fp1) fclose(fp1);
  884.     return(STATE_ERRFILE);
  885.   }
  886.   { char *mode= (JP_APPEND(jobparm->flags)) ? ("a") : ("w");
  887.     if(!(fpo= fopen(jobparm->outfile,mode)))
  888.     { perror("File-Error: Unable to open %s.",jobparm->outfile);
  889.       if(fp1) fclose(fp1);
  890.       if(fp2) fclose(fp2);
  891.       return(STATE_ERRPRT);
  892.     }
  893.   }
  894.  
  895.   /* allocate line buffer */
  896.  
  897.   if(!(buf=(char *)alloc_mem(jobparm->charct)))
  898.   { perror("Fatal-Error: Unable to allocate %ld bytes of memory.",
  899.       jobparm->charct);
  900.     if(fp1) fclose(fp1);
  901.     if(fp2) fclose(fp2);
  902.     if(fpo) fclose(fpo);
  903.     return(STATE_NOMEM);
  904.   }
  905.  
  906.   skip_lines(fp2, jobparm->linect);
  907.   term_clear;
  908.  
  909.   if(!feof(fp2))
  910.   { char fmt[20];
  911.     char *s,
  912.          *header=NULL,
  913.          *footer=NULL;
  914.     long l=0,
  915.          p=jobparm->firstpage;
  916.  
  917.     int  linect= jobparm->linect;
  918.  
  919.     if(JP_HEADING(jobparm->flags))
  920.     { linect-= HEADERLINES;
  921.       header= make_heading(jobparm);
  922.       fwrite(header, sizeof(char), strlen(header), fpo);
  923.     }
  924.  
  925.     if(JP_FOOTING(jobparm->flags))
  926.     { linect-= FOOTERLINES;
  927.       footer= make_footing(jobparm,p);
  928.     }
  929.     sprintf(fmt,"%%-%lds | ",jobparm->charct/jobparm->columns);
  930.  
  931.     while(!(feof(fp1) || feof(fp2)))
  932.     { for(s=buf;((*s=fgetc(fp1))!=LF) && !feof(fp1); s++)
  933.         ;
  934.       *s='\0';
  935.       fprintf(fpo,fmt,buf);
  936.       for(s=buf;((*s=fgetc(fp2))!=LF) && !feof(fp2); s++)
  937.         ;
  938.       *++s='\0';
  939.       if(!feof(fp2))
  940.       { fputs(buf,fpo);
  941.         l++;
  942.         if((l%linect)==0)
  943.         { skip_lines(fp1, jobparm->linect);
  944.           skip_lines(fp2, jobparm->linect);
  945.           term_write(l);
  946.           if(footer)
  947.           { fwrite(footer,sizeof(char),strlen(footer),fpo);
  948.             footer= make_footing(jobparm, ++p);
  949.           }
  950.           if(header) fwrite(header,sizeof(char),strlen(header),fpo);
  951.         }
  952.       }
  953.     }
  954.   }
  955.   free_mem(buf);
  956.   if(fp2) fclose(fp2);
  957.   if(fp1) fclose(fp1);
  958.   if(fpo) fclose(fpo);
  959.   return(STATE_OKAY);
  960. }
  961.  
  962. /*
  963.  * print a file
  964.  */
  965.  
  966. int print_file(jobparm,jobstate)
  967. struct jobparm *jobparm;
  968. struct jobstate *jobstate;
  969. { static unsigned long pageno=1;
  970.  
  971.   FILE *fpi,  /* input stream */
  972.        *fpo;  /* output stream */
  973.  
  974.   char *buf;       /* line buffer */
  975.   long b=0,        /* general counter */
  976.        inln=0,     /* lines of input */
  977.        outln=0,    /* lines of output */
  978.        wraps=0,    /* #of word wraps */
  979.        cracks=0,   /* #of line breaks */
  980.        cleanups=0, /* #of invisible chars */
  981.        fillups=0;  /* #of empty lines added */
  982.  
  983.   int  indent = jobparm->indent,
  984.        charct = jobparm->charct,
  985.        linect = jobparm->linect,
  986.        tabsize= jobparm->tabsize,
  987.        flags  = jobparm->flags;
  988.  
  989.   char *header= (char *)NULL;      /* page header */
  990.  
  991.   /* open input- and output stream */
  992.  
  993.   if(jobparm->infile && *(jobparm->infile))
  994.   { if(!(fpi=fopen(jobparm->infile,"r")))
  995.     { perror("Error: Unable to open `%s'.\n",jobparm->infile);
  996.       return(STATE_ERRFILE);
  997.     }
  998.     if(jobparm->columns > 1)
  999.     { if(!(fpo= fopen(TEMPNAME, "w")))
  1000.       { perror("Error: Unable to write temorary data to %s.\n",TEMPNAME);
  1001.         if(fpi) fclose(fpi);
  1002.         return(STATE_ERRPRT);
  1003.       }
  1004.       charct /= jobparm->columns;
  1005.       if(JP_HEADING(flags))
  1006.       { linect-= (HEADERLINES * (jobparm->columns -1) );
  1007.         flags&= ~JPFLAG_HEADING;
  1008.       }
  1009.       if(JP_FOOTING(flags))
  1010.       { linect-= (FOOTERLINES * (jobparm->columns -1) );
  1011.         flags&= ~JPFLAG_FOOTING;
  1012.       }
  1013.     }
  1014.     else
  1015.     { char *mode= (JP_APPEND(flags)) ? ("a") : ("w");
  1016.       if(!(fpo= fopen(jobparm->outfile,mode)))
  1017.       { perror("Error: Unable to open %s.\n",jobparm->outfile);
  1018.         if(fpi) fclose(fpi);
  1019.         return(STATE_ERRPRT);
  1020.       }
  1021.     }
  1022.   }
  1023.   else return(STATE_ERRFILE); /* nothing to print */
  1024.  
  1025.   /* init printer */
  1026.  
  1027.   if(JP_MINI(flags))
  1028.     fprintf(fpo,INITMINI);  /* begin with superscript */
  1029.   else if(!JP_PLAIN(flags))
  1030.   { if(dltype(ENV_VOLUME)!=DLT_UNKNOWN) /* env: exists */
  1031.     { FILE *fpx=fopen(INITPRINTER,"r");
  1032.       if(fpx)
  1033.       { char c;
  1034.         printf("%s found, printer installed.\n",INITPRINTER);
  1035.         while((c=fgetc(fpx))!=EOF && !feof(fpx))
  1036.         { fputc(c,fpo);
  1037.           if(c=='\n')
  1038.            outln++;
  1039.           }
  1040.         fclose(fpx);
  1041.       }
  1042.     }
  1043.   }
  1044.  
  1045.   if(!(buf=(char *)alloc_mem(charct)))
  1046.   { perror("Fatal-Error: Unable to allocate %ld bytes of memory.",
  1047.       charct);
  1048.     if(fpi) fclose(fpi);
  1049.     if(fpo) fclose(fpo);
  1050.     return(STATE_NOMEM);
  1051.   }
  1052.   for(b=0;b<indent;b++) /* init indention */
  1053.     buf[b]=' ';
  1054.   if(jobparm->leader)
  1055.   { strcpy(&buf[indent],jobparm->leader);
  1056.     indent+=strlen(jobparm->leader);
  1057.   }
  1058.   b= indent;
  1059.  
  1060.   printf("        %s => %s\r",jobparm->infile,jobparm->outfile);
  1061.  
  1062.   /* skip lines */
  1063.  
  1064.   if(jobparm->lineskip>0)
  1065.   { int skip= jobparm->lineskip;
  1066.     if(skip<0)
  1067.       skip= -skip*linect; /* skip pages */
  1068.     if(skip>0)
  1069.       skip_lines(fpi,skip);
  1070.   }
  1071.  
  1072.   if(jobparm->firstpage != 0)
  1073.     pageno= jobparm->firstpage;
  1074.   else jobparm->firstpage= pageno;
  1075.  
  1076.   if(JP_HEADING(flags))
  1077.   { header= make_heading(jobparm);
  1078.     linect-= HEADERLINES;
  1079.   }
  1080.   if(JP_FOOTING(flags))
  1081.     linect-= FOOTERLINES;
  1082.  
  1083.   /* main loop */
  1084.  
  1085.   { BOOL pbrk, lbrk;  /* page break, line break read */
  1086.     char *rbuf;
  1087.     int refresh=(linect>1)?(linect):(DEFREFRESH);
  1088.                       /* when to print out the current line number */
  1089.  
  1090.     while(!feof(fpi))
  1091.     { rbuf=&buf[b]; /* b==indent */
  1092.       do
  1093.       { *rbuf=fgetc(fpi);
  1094.         if(*rbuf==TAB && tabsize>0)
  1095.         { do
  1096.           { *rbuf++=' ';
  1097.             b++;
  1098.           }
  1099.           while((b%tabsize) && b<charct);
  1100.           lbrk=pbrk=FALSE;
  1101.         }
  1102.         else
  1103.         { lbrk=(*rbuf==LF);
  1104.           pbrk=(*rbuf==FF);
  1105.           b++;
  1106.           rbuf++;
  1107.         }
  1108.       } while(b<charct && !(pbrk || lbrk || feof(fpi)));
  1109.  
  1110.       rbuf--; /* set to the character read last
  1111.                * b = #of chars in buf[]
  1112.                */
  1113.  
  1114.       if(lbrk)
  1115.       { inln++;  /* we've read a complete line */
  1116.         if(inln%refresh==0)
  1117.           term_write(inln);   /* we're alive ! */
  1118.       }
  1119.  
  1120.       if(b<charct || lbrk || pbrk || feof(fpi) )
  1121.       { --rbuf;  /* => don't write the character read last */
  1122.         --b;
  1123.       }
  1124.  
  1125.       if(JP_CLEANUP(flags)) /* => remove invisible chars */
  1126.       { while((*rbuf==' '||*rbuf=='\t') && b>0)
  1127.         { --rbuf;
  1128.           --b;
  1129.           cleanups++;
  1130.         }
  1131.       }
  1132.  
  1133.       if(header && (outln%linect)==0)
  1134.         fwrite(header, sizeof(char), strlen(header), fpo);
  1135.  
  1136.       if(b<charct)  /* => normal line */
  1137.       { if((feof(fpi) && b>indent) || (!feof(fpi) && b>0))
  1138.           fwrite(buf,sizeof(char),b,fpo);
  1139.         newline(fpo,flags);
  1140.         outln++;
  1141.         /*
  1142.          * We increase outln in any case, since the first line on a new
  1143.          * page terminated without '\n' would imply (outln%linect) to
  1144.          * be ==0 and this page would NOT be filled up if an EOF follows.
  1145.          * note that a file ending without a '\n' character will get it from
  1146.          * lp in any case.
  1147.          */
  1148.         b=indent;
  1149.       }
  1150.       else /* line too long */
  1151.       { int bp=b-1; /* break,wrap position */
  1152.  
  1153.         /* search for a word wrap position */
  1154.         while(buf[bp]!=' ' && buf[bp]!='\t' && --bp>indent);
  1155.  
  1156.         if(bp>indent) /* => confirm word wrap */
  1157.         { int i;
  1158.           fwrite(buf,sizeof(char),bp,fpo);
  1159.           newline(fpo,flags);
  1160.           outln++;
  1161.           bp++;  /* skip word terminating character */
  1162.           for(i=0;i<b-bp;i++) buf[indent+i]=buf[bp+i];
  1163.           b=indent+i;
  1164.           wraps++;
  1165.         }
  1166.  
  1167.         else /* => break line... we've got no choice */
  1168.         { fwrite(buf,sizeof(char),b,fpo);
  1169.           newline(fpo,flags);
  1170.           outln++;
  1171.           b=indent;
  1172.           cracks++;
  1173.         }
  1174.       }
  1175.  
  1176.       /* handle form feed character */
  1177.       if(pbrk && (outln%linect) > 0)
  1178.       { int al= linect-(outln%linect);  /* #of additional lines */
  1179.         /* Warning:
  1180.          * If (outln%lincet)==0 we would add another lincet lines to
  1181.          * the output without increasing/printing the page number and a
  1182.          * new header! So: If a header and/or footer were also toggled,
  1183.          * linect would not be enough to fill up a full page since we
  1184.          * decreased it by headerlines and/or footerlines!!!
  1185.          */
  1186.         if(JP_USEFF(flags))
  1187.           fputc(FF, fpo);
  1188.         else
  1189.         { int i;
  1190.           for(i=0;i<al;i++) newline(fpo,flags);
  1191.           fillups+=al;
  1192.         }
  1193.         outln+=al;
  1194.         
  1195.       }
  1196.  
  1197.       if((outln%linect)==0)
  1198.       { if(JP_FOOTING(flags))
  1199.         { char *s= make_footing(jobparm, pageno);
  1200.           fwrite(s,sizeof(char),strlen(s),fpo);
  1201.         }
  1202.         pageno++;
  1203.       }
  1204.     }
  1205.     if(JP_FEEDOUT(flags))
  1206.     { linect*= jobparm->columns;
  1207.       for(b=0;(outln%linect)!=0;outln++,b++)
  1208.         newline(fpo,flags); /* feed out last page */
  1209.       fillups+=b;
  1210.  
  1211.       /* take care: (here was a bug v1.16)
  1212.        * if(b==0) we've already added the footer ! */
  1213.       if(b>0)
  1214.       { if(JP_FOOTING(flags))
  1215.         { char *s= make_footing(jobparm, pageno);
  1216.           fwrite(s,sizeof(char),strlen(s),fpo);
  1217.         }
  1218.         pageno++;
  1219.       }
  1220.     }
  1221.   }
  1222.   if(JP_MINI(flags))
  1223.     fprintf(fpo, INITNOMINI);  /* turn off all special modi at the EOF */
  1224.  
  1225.   if(buf) free_mem(buf);
  1226.  
  1227.   if(fpi) fclose(fpi);
  1228.   if(fpo) fclose(fpo);
  1229.  
  1230.   jobstate->inln     = inln;
  1231.   jobstate->outln    = outln;
  1232.   jobstate->wraps    = wraps;
  1233.   jobstate->cracks   = cracks;
  1234.   jobstate->cleanups = cleanups;
  1235.   jobstate->fillups  = fillups;
  1236.  
  1237.   if(jobparm->columns>1)
  1238.     join_columns(jobparm);
  1239.  
  1240.   return(STATE_OKAY);
  1241. }
  1242.  
  1243. /* write the statistics into our logfile */
  1244.  
  1245. void statistics(struct jobparm *jp,
  1246.                 struct jobstate *js )
  1247. { FILE *sf;
  1248.   sf=fopen(LOGFILENAME,"a");
  1249.   if(sf)
  1250.   { long flags= jp->flags;
  1251.  
  1252.     fprintf(sf,"%s (%d+%d lines, %d cleaned, %d wraped, %d broken)\n",
  1253.                                                    jp->infile,
  1254.                                                    js->inln,
  1255.                                                    js->fillups,
  1256.                                                    js->cleanups,
  1257.                                                    js->wraps,
  1258.                                                    js->cracks );
  1259.  
  1260.     fprintf(sf,"jobparm -i%d -w%d -h%d -t%d -c%d ",jp->indent,
  1261.                                                    jp->charct,
  1262.                                                    jp->linect,
  1263.                                                    jp->tabsize,
  1264.                                                    jp->columns );
  1265.  
  1266.     if(JP_PLAIN(flags))       fprintf(sf,"-p ");  else fprintf(sf,"+p ");
  1267.     if(JP_AUTOLF(flags))      fprintf(sf,"-e ");  else fprintf(sf,"+e ");
  1268.     if(JP_MINI(flags))        fprintf(sf,"-m ");  else fprintf(sf,"+m ");
  1269.     if(JP_USEFF(flags))       fprintf(sf,"-f ");  else fprintf(sf,"+f ");
  1270.     if(JP_CLEANUP(flags))     fprintf(sf,"+d ");  else fprintf(sf,"-d ");
  1271.     if(jp->leader)            fprintf(sf,"-l \"%s\" ",jp->leader);
  1272.     if(jp->lineskip > 0)      fprintf(sf,"-s %d ",jp->lineskip);
  1273.     else if(jp->lineskip < 0) fprintf(sf,"-n %d ",-(jp->lineskip));
  1274.     if(JP_REPLACE(flags))     fprintf(sf,"-r ");
  1275.     if(JP_APPEND(flags))      fprintf(sf,"-a ");  else fprintf(sf,"+a ");
  1276.     if(jp->outfile)           fprintf(sf,"-o \"%s\" ",jp->outfile);
  1277.     if(JP_HEADING(flags))     fprintf(sf,"-n ");  else fprintf(sf,"+n ");
  1278.     if(JP_FEEDOUT(flags))     fprintf(sf,"-x ");  else fprintf(sf,"+x ");
  1279.     if(JP_DOUBLESIDED(flags)) fprintf(sf,"-2 %d ",jp->firstpage);
  1280.     if(JP_SINGLESIDED(flags)) fprintf(sf,"-1 %d ",jp->firstpage);
  1281.     if(!JP_FOOTING(flags))    fprintf(sf,"+0 ");
  1282.     fprintf(sf,"\n\n");
  1283.     fclose(sf);
  1284.   }
  1285. }
  1286.  
  1287. /*
  1288.  * submit all print jobs in given jobparm list
  1289.  */
  1290.  
  1291. int submit_printjob(jobparm)
  1292. struct jobparm *jobparm;
  1293. { int state= STATE_OKAY;
  1294.   struct jobstate jobstate;
  1295.  
  1296.   if(jobparm)
  1297.   { if(jobparm->infile && *(jobparm->infile) &&
  1298.       jobparm->outfile && *(jobparm->outfile) )
  1299.     { state= print_file(jobparm, &jobstate);
  1300.       if(state==STATE_OKAY)
  1301.       { if(JP_REPLACE(jobparm->flags))
  1302.         { DeleteFile(jobparm->infile);
  1303.           Rename(jobparm->outfile,jobparm->infile);
  1304.         }
  1305.         printf("   %s => %s [printed]\n",jobparm->infile, jobparm->outfile);
  1306.         statistics(jobparm, &jobstate);
  1307.       }
  1308.     }
  1309.     if(state==STATE_OKAY && jobparm->next)
  1310.       state= submit_printjob(jobparm->next);
  1311.   }
  1312.   return(state);
  1313. }
  1314.  
  1315. /*
  1316.  * here we build the whole jobparm-list out of main()'s arguments
  1317.  */
  1318.  
  1319. struct jobparm *build_joblist(int argc, char *argv[])
  1320. { struct jobparm *mainjob;  /* head of the jobparm-list */
  1321.   int state= STATE_OKAY;
  1322.   mainjob= alloc_jobparm(NULL);
  1323.   if(mainjob)
  1324.   { struct jobparm *jobparm= mainjob; /* working pointer */
  1325.     jobparm= tail(jobparm);
  1326.     jobparm->next= alloc_jobparm(jobparm);
  1327.     jobparm= jobparm->next;
  1328.     if(jobparm)
  1329.     { arglist2jobparm(jobparm, argc, argv);
  1330.       check_jobparm(jobparm,0,"command-line");
  1331.       if(jobparm->tocfile)
  1332.         state= file2jobparm(jobparm, jobparm->tocfile);
  1333.     }
  1334.     else
  1335.     { perror("Not enough memory to parse command line!");
  1336.       state= STATE_NOMEM;
  1337.     }
  1338.   }
  1339.   else
  1340.   { perror("Not enough memory to allocate print job!");
  1341.     state= STATE_NOMEM;
  1342.   }
  1343.  
  1344.   if((state!=STATE_OKAY) && mainjob)
  1345.   { free_jobparm(mainjob);
  1346.     mainjob= (struct jobparm *)NULL;
  1347.   }
  1348.  
  1349.   return(mainjob);
  1350. }
  1351.  
  1352. void main(int argc, char *argv[])
  1353. { int state;    /* job state after execution attempt */
  1354.   struct jobparm *jobparm;
  1355.   onbreak(_abort);  /* this is DICE */
  1356.  
  1357.   puts(BANNER); /* let me introduce myself... */
  1358.   if(argc==2 && (argv[1][0]=='?' || argv[1][0]=='.'))
  1359.   { char **s= howtouse;
  1360.     puts(USAGE);
  1361.     puts("\nLegal options are:\n");
  1362.     if(argv[1][0]=='?') while(*s)
  1363.     { printf("%-11s %s %s\n",s[0],s[2],s[3]);
  1364.       s= &s[4];
  1365.     }
  1366.     else while(*s)
  1367.     { printf("%-2s %s %s\n",s[1],s[2],s[3]);
  1368.       s= &s[4];
  1369.     }
  1370.     puts("\nALL THIS IS HIGHLY EXPERIMENTAL !!! TAKE GREAT CARE !!!");
  1371.     exit(0);
  1372.   }
  1373.  
  1374.   whoami=argv[0]; /* who am I ? */
  1375.   argc--;
  1376.   argv++; /* skip our name */
  1377.  
  1378.   jobparm= build_joblist(argc, argv);
  1379.   if(jobparm)
  1380.   { DeleteFile(LOGFILENAME);
  1381.     state= submit_printjob(jobparm);
  1382.   }
  1383.   free_jobparm(jobparm);
  1384.   exit((state==STATE_OKAY)?(0):(1));
  1385. }
  1386.