home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / pr2 / pr2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-10  |  13.1 KB  |  593 lines

  1. /***********************************************************
  2. **
  3. **  pr2.c   --  a new (better?) file paginator
  4. **
  5. **  usage:
  6. **      pr2  [options/filenames...]
  7. **
  8. **  options:
  9. **      -T <#>      Set number of rows in the top margin.
  10. **      -B <#>      Set number of rows in the bottom margin.
  11. **      -L <#>      Set number of cols in the left margin.
  12. **      -R <#>      Set number of cols in the right margin.
  13. **      -w <#>      Set number of cols on a page.
  14. **      -l <#>      Set number of rows on a page.
  15. **      -s <#>      Set the line spacing.
  16. **      -p <#>      Set the page number.
  17. **      -pr         Set page numbering to roman numerals
  18. **      -pa         Set page numbering to arabic numerals
  19. **
  20. **      -t#text     Assign 'text' to title # and turn it on.
  21. **      -h#[yn]     Turn title # on or off.
  22. **      -h#[tb][lcr]
  23. **                  Set the position of the title:  t=top,
  24. **                  b=bottom, l=left, c=center, r=right.
  25. **                  Examples: tc=top center, bl=bottom left.
  26. **
  27. **      -v          Displays the version number of pr2.  If
  28. **                  this option is given and no files are
  29. **                  specified on the command line, pr2 will
  30. **                  quit immediately rather than wait for
  31. **                  text from standard input.
  32. **
  33. **  $Revision: 2.2 $
  34. **
  35. **    $Author: jearls $
  36. **      $Date: 91/12/02 12:03:13 $
  37. **
  38. **  Modification History:  $Log:    pr2.c,v $
  39. **      Revision 2.2  91/12/02  12:03:13  jearls
  40. **      Added -v option
  41. **      
  42. **      Revision 2.1  91/11/24  10:10:24  jearls
  43. **      Added -s option for line spacing.
  44. **      Added usage info to header for -t, -h, -s.
  45. **      
  46. **      Revision 2.0  91/11/24  00:57:58  jearls
  47. **      Initial Revision
  48. **      
  49. ***********************************************************/
  50.  
  51. #include <stdio.h>
  52. #include <strings.h>
  53. #include <ctype.h>
  54.  
  55. typedef struct  Title
  56. {
  57.   char   *text;
  58.   int     pos;    /* 1 = left, 2 = right, 3 = center */
  59.   int     header; /* 1 = header, 0 = footer */
  60.   int     flag;   /* 1 = print, 0 = don't */
  61. } Title;
  62.  
  63. typedef struct  Page
  64. {
  65.   int rows, cols, top, bottom, left, right;
  66. } Page;
  67.  
  68. static  Title   titles[6] =
  69. {
  70.   { "%f", 3, 1, 1 },
  71.   { "- %p -", 3, 0, 1 },
  72.   { "", 1, 1, 0 },
  73.   { "", 2, 1, 0 },
  74.   { "", 1, 0, 0 },
  75.   { "", 2, 0, 0 }
  76. } ;
  77.  
  78. static  Page    page = { 66, 80, 6, 6, 10, 10 };
  79.  
  80. static  int     linenum = 0, charnum = 0,
  81.                 pagenum = 1, pageform = 1,  /* 0 = roman, 1 = arabic */
  82.                 lineSpacing = 1;
  83. static  char   *curFilename, *progName, pagestr[10];
  84.  
  85. char   *strdup(char *s)
  86. {
  87.   char *p;
  88.  
  89.   p = (char *)malloc(1+strlen(s));
  90.   if (p)
  91.     (void)strcpy(p, s);
  92.   return(p);
  93. }
  94.  
  95. char   *instr(char *str, char *sub)
  96. {
  97.   char *p, *q, *index();
  98.  
  99.   while (str = index(str, *sub))
  100.   {
  101.     p = str; q = sub;
  102.     while (*(++q) && ((*++p) == (*q)));
  103.     if (!(*q))
  104.       return(str);
  105.     str++;
  106.   }
  107.   return((char *)NULL);
  108. }
  109.  
  110. char   *subst(char *orig, char *old, char *new)
  111. {
  112.   char *p, *q;
  113.   int expand = strlen(new)-strlen(old) + 1;
  114.  
  115.   while(q = instr(orig, old))
  116.   {
  117.     p = (char *)malloc(strlen(orig) + expand);
  118.     *q = '\0';
  119.     (void)strcpy(p, orig);
  120.     (void)strcat(p, new);
  121.     (void)strcat(p, q+strlen(old));
  122.     free(orig);
  123.     orig = p;
  124.   }
  125.  
  126.   return(orig);
  127. }
  128.  
  129. void    addTitle(char *line, Title title, int header)
  130. {
  131.   char   *txt, *p;
  132.   int     col, len;
  133.  
  134.   if ((title.flag) && (title.header == header))
  135.   {
  136.     txt = strdup(title.text);
  137.     txt = subst(txt, "%f", curFilename);
  138.     txt = subst(txt, "%p", pagestr);
  139.     col = 0;
  140.     if (title.pos != 1)
  141.       col = page.cols - page.right - strlen(txt);
  142.     if (title.pos == 3)
  143.       col = (col - page.left) / 2;
  144.     if (title.pos != 2)
  145.       col += page.left;
  146.     len = strlen(line);
  147.     while (len < col)
  148.       line[len++] = ' ';
  149.     p = txt;
  150.     while (*txt)
  151.       line[col++] = *(txt++);
  152.     if (col > len)
  153.       line[col] = '\0';
  154.     free(p);
  155.   }
  156. }
  157.  
  158. void addRoman(char **s, int num, int pos, char c1, char c5, char c10)
  159. {
  160.   int dig = (num/pos) % 10;
  161.  
  162.   if (dig == 9)
  163.   {
  164.     *((*s)++) = c1;
  165.     *((*s)++) = c10;
  166.   } else
  167.     if (dig == 4)
  168.     {
  169.       *((*s)++) = c1;
  170.       *((*s)++) = c5;
  171.     } else {
  172.       if (dig > 4)
  173.         *((*s)++) = c5;
  174.       dig %= 5;
  175.       while (dig--)
  176.         *((*s)++) = c1;
  177.     }
  178. }
  179.  
  180. void roman(char *s, int num)
  181. {
  182.   addRoman(&s, num, 1000, 'm', '?', '?');
  183.   num %= 1000;
  184.   addRoman(&s, num, 100, 'c', 'd', 'm');
  185.   num %= 100;
  186.   addRoman(&s, num, 10, 'x', 'l', 'c');
  187.   num %= 10;
  188.   addRoman(&s, num, 1, 'i', 'v', 'x');
  189.   *s = '\0';
  190. }
  191.  
  192. void    print_header()
  193. {
  194.   char *line;
  195.   int lp;
  196.  
  197.   if (page.top > 1)
  198.   {
  199.     if (pageform)
  200.       (void)sprintf(pagestr, "%d", pagenum);
  201.     else
  202.       roman(pagestr, pagenum);
  203.  
  204.     line = (char *)malloc(page.cols);
  205.     *line = '\0';
  206.  
  207.     for (lp=0; lp<6; lp++)
  208.       addTitle(line, titles[lp], 1);
  209.  
  210.     linenum = lp = (page.top - 1) / 2;
  211.  
  212.     while (lp--)
  213.       putchar('\n');
  214.  
  215.     puts(line);
  216.     free(line);
  217.  
  218.     linenum++;
  219.   }
  220.  
  221.   while (linenum < page.top)
  222.   {
  223.     putchar('\n');
  224.     linenum++;
  225.   }
  226.  
  227.   charnum = 0;
  228. }
  229.  
  230. void    print_footer()
  231. {
  232.   char *line;
  233.   int lp;
  234.  
  235.   if (page.bottom > 1)
  236.   {
  237.     if (pageform)
  238.       (void)sprintf(pagestr, "%d", pagenum++);
  239.     else
  240.       roman(pagestr, pagenum++);
  241.  
  242.     line = (char *)malloc(page.cols);
  243.     *line = '\0';
  244.  
  245.     for (lp=0; lp<6; lp++)
  246.       addTitle(line, titles[lp], 0);
  247.  
  248.     linenum += lp = page.bottom / 2;
  249.  
  250.     while (lp--)
  251.       putchar('\n');
  252.  
  253.     puts(line);
  254.     free(line);
  255.  
  256.     linenum++;
  257.   }
  258.  
  259.   while (linenum < page.rows)
  260.   {
  261.     putchar('\n');
  262.     linenum++;
  263.   }
  264.  
  265.   linenum = charnum = 0;
  266. }
  267.  
  268. void    out(char c)
  269. {
  270.   int lp;
  271.  
  272.   if ((isprint(c)) || (isspace(c)))
  273.   {
  274.     if ((c != '\014') && (linenum == page.rows - page.bottom))
  275.       print_footer();
  276.     if (linenum < page.top)
  277.       print_header();
  278.     if (isprint(c))
  279.     {
  280.       if (charnum == page.cols - page.right)
  281.       out('\n');
  282.       while (charnum < page.left)
  283.       {
  284.         putchar(' ');
  285.         charnum++;
  286.       }
  287.       putchar(c);
  288.       charnum++;
  289.     } else
  290.       switch(c)
  291.       {
  292.         case '\t'     :
  293.           out(' ');
  294.           while ((charnum - page.left) % 8)
  295.             out(' ');
  296.           break;
  297.         case '\r'     :
  298.         case '\013'   :
  299.         case '\n'     :
  300.           for (lp=lineSpacing; lp--;)
  301.           {
  302.             if (linenum == page.rows - page.bottom)
  303.             {
  304.               print_footer();
  305.               print_header();
  306.             }
  307.             putchar('\n');
  308.             linenum++;
  309.           }
  310.           charnum = 0;
  311.           break;
  312.         case '\014'   :
  313.           while (linenum < page.rows-page.bottom)
  314.             out('\n');
  315.           print_footer();
  316.           break;
  317.         }
  318.     }
  319. }
  320.  
  321. void doFile(char *fn)
  322. {
  323.   int c;
  324.   FILE *f;
  325.  
  326.   if (curFilename = fn)
  327.     f = fopen(fn, "r");
  328.   else
  329.   {
  330.     curFilename = "stdin";
  331.     f = stdin;
  332.   }
  333.  
  334.   if (f == (FILE *)NULL)
  335.     perror(fn);
  336.   else
  337.   {
  338.     while ((c = getc(f)) != EOF)
  339.       out((char)c);
  340.     if (linenum)
  341.       out('\014');
  342.  
  343.     if (fn)
  344.       fclose(f);
  345.   }
  346. }
  347.  
  348. void usage(char *err)
  349. {
  350.   fprintf(stderr, "%s:  %s\n", progName, err);
  351.   exit(1);
  352. }
  353.  
  354. int isnumber(char *s)
  355. {
  356.   if (!(*s)) return(0);
  357.   while ((*s) && (isdigit(*s))) s++;
  358.   return(!(*s));
  359. }
  360.  
  361. void main(int argc, char **argv)
  362. {
  363.   int fileFlag = 0, tmp, tmp2;
  364.   char buf[128], *p;
  365.  
  366.   progName = *argv;
  367.  
  368.   while (--argc) 
  369.     if (**(++argv) == '-')
  370.     {
  371.       switch((p = *argv)[1])
  372.       {
  373.         case 'T' :
  374.           if (p[2])
  375.             if (isnumber(p+2))
  376.               page.top = atoi(p+2);
  377.             else
  378.               usage("-T :  Numeric argument needed.");
  379.           else if (argc--)
  380.             if (isnumber(*(++argv)))
  381.               page.top = atoi(*argv);
  382.             else
  383.               usage("-T :  Numeric argument needed.");
  384.           else
  385.             usage("-T :  Numeric argument needed.");
  386.           break;
  387.  
  388.         case 'B' :
  389.           if (p[2])
  390.             if (isnumber(p+2))
  391.               page.bottom = atoi(p+2);
  392.             else
  393.               usage("-B :  Numeric argument needed.");
  394.           else if (argc--)
  395.             if (isnumber(*(++argv)))
  396.               page.bottom = atoi(*argv);
  397.             else
  398.               usage("-B :  Numeric argument needed.");
  399.           else
  400.             usage("-B :  Numeric argument needed.");
  401.           break;
  402.  
  403.         case 'L' :
  404.           if (p[2])
  405.             if (isnumber(p+2))
  406.               page.left = atoi(p+2);
  407.             else
  408.               usage("-L :  Numeric argument needed.");
  409.           else if (argc--)
  410.             if (isnumber(*(++argv)))
  411.               page.left = atoi(*argv);
  412.             else
  413.               usage("-L :  Numeric argument needed.");
  414.           else
  415.             usage("-L :  Numeric argument needed.");
  416.           break;
  417.  
  418.         case 'R' :
  419.           if (p[2])
  420.             if (isnumber(p+2))
  421.               page.right = atoi(p+2);
  422.             else
  423.               usage("-R :  Numeric argument needed.");
  424.           else if (argc--)
  425.             if (isnumber(*(++argv)))
  426.               page.right = atoi(*argv);
  427.             else
  428.               usage("-R :  Numeric argument needed.");
  429.           else
  430.             usage("-R :  Numeric argument needed.");
  431.           break;
  432.  
  433.         case 'l' :
  434.           if (p[2])
  435.             if (isnumber(p+2))
  436.               page.rows = atoi(p+2);
  437.             else
  438.               usage("-l :  Numeric argument needed.");
  439.           else if (argc--)
  440.             if (isnumber(*(++argv)))
  441.               page.rows = atoi(*argv);
  442.             else
  443.               usage("-l :  Numeric argument needed.");
  444.           else
  445.             usage("-l :  Numeric argument needed.");
  446.           break;
  447.  
  448.         case 'w' :
  449.           if (p[2])
  450.             if (isnumber(p+2))
  451.               page.cols = atoi(p+2);
  452.             else
  453.               usage("-w :  Numeric argument needed.");
  454.           else if (argc--)
  455.             if (isnumber(*(++argv)))
  456.               page.cols = atoi(*argv);
  457.             else
  458.               usage("-w :  Numeric argument needed.");
  459.           else
  460.             usage("-w :  Numeric argument needed.");
  461.           break;
  462.  
  463.         case 's' :
  464.           if (p[2])
  465.             if (isnumber(p+2))
  466.               lineSpacing = atoi(p+2);
  467.             else
  468.               usage("-s :  Numeric argument needed.");
  469.           else if (argc--)
  470.             if (isnumber(*(++argv)))
  471.               lineSpacing = atoi(*argv);
  472.             else
  473.               usage("-s :  Numeric argument needed.");
  474.           else
  475.             usage("-s :  Numeric argument needed.");
  476.           break;
  477.  
  478.         case 'p' :
  479.           if (p[2])
  480.         if (p[2] == 'a')
  481.           pageform = 1;
  482.         else
  483.           if (p[2] == 'r')
  484.         pageform = 0;
  485.           else
  486.         if (isnumber(p+2))
  487.           pagenum = atoi(p+2);
  488.         else
  489.           usage("-p :  Numeric argument needed.");
  490.           else if (argc--)
  491.             if (isnumber(*(++argv)))
  492.               pagenum = atoi(*argv);
  493.             else
  494.               usage("-p :  Numeric argument needed.");
  495.           else
  496.             usage("-p :  Numeric argument needed.");
  497.           break;
  498.  
  499.         case 't' :
  500.           if ((p[2] < '1') || (p[2] > '6'))
  501.           {
  502.             (void)sprintf(buf,
  503.               "-t:  %c:  Illegal title specifier.", p[2]);
  504.             usage(buf);
  505.           }
  506.  
  507.           tmp = p[2] - '1';
  508.           p += 3;
  509.           if ((!(*p)) && (argc))
  510.           {
  511.             p = *(++argv);
  512.             argc--;
  513.           }
  514.           if (!(*p))
  515.           {
  516.             fprintf(stderr,
  517.               "Warning:  no text given for title %d; ",
  518.               tmp);
  519.             fprintf(stderr,
  520.               "turning title off and clearing.\n");
  521.             titles[tmp].flag = 0;
  522.           } else
  523.             titles[tmp].flag = 1;
  524.  
  525.           titles[tmp].text = p;
  526.           break;
  527.  
  528.         case 'h' :
  529.           if ((p[2] < '1') || (p[2] > '6'))
  530.           {
  531.             (void)sprintf(buf,
  532.               "-h:  %c:  Illegal title specifier.", p[2]);
  533.             usage(buf);
  534.           }
  535.  
  536.           tmp = p[2] - '1';
  537.           switch (p[3])
  538.           {
  539.             case 'Y'  :
  540.             case 'y'  : titles[tmp].flag = 1;
  541.                         tmp = -1; break;
  542.             case 'N'  :
  543.             case 'n'  : titles[tmp].flag = 0;
  544.                         tmp = -1; break;
  545.             case 'T'  :
  546.             case 't'  : titles[tmp].header = 1; break;
  547.             case 'B'  :
  548.             case 'b'  : titles[tmp].header = 0; break;
  549.             default   : sprintf(buf,
  550.                           "%s:  Illegal title position.",
  551.                           *argv);
  552.                         usage(buf);
  553.           }
  554.  
  555.           if (tmp > -1)
  556.             switch(p[4])
  557.             {
  558.               case 'L'  :
  559.               case 'l'  : titles[tmp].pos = 1; break;
  560.               case 'R'  :
  561.               case 'r'  : titles[tmp].pos = 2; break;
  562.               case 'C'  :
  563.               case 'c'  : titles[tmp].pos = 3; break;
  564.               default   : sprintf(buf,
  565.                             "%s:  Illegal title position.",
  566.                             *argv);
  567.                           usage(buf);
  568.             }
  569.           break;
  570.  
  571.     case 'v'  :
  572.       puts("$Revision: 2.2 $");
  573.       fileFlag = 1;
  574.       break;
  575.  
  576.         case '\0' :
  577.           doFile(NULL);
  578.           fileFlag = 1;
  579.           break;
  580.  
  581.         default :
  582.           (void)sprintf(buf, "-%c :  Unknown flag.", p[1]);
  583.           usage(buf);
  584.       }
  585.     } else {
  586.       doFile(*argv);
  587.       fileFlag = 1;
  588.     }
  589.  
  590.   if (!fileFlag)
  591.     doFile(NULL);
  592. }
  593.