home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / Mail / fmt.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  7KB  |  384 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #
  3.  
  4. #include <stdio.h>
  5.  
  6. /*
  7.  * fmt -- format the concatenation of input files or standard input
  8.  * onto standard output.  Designed for use with Mail ~|
  9.  *
  10.  * Syntax: fmt [ name ... ]
  11.  * Author: Kurt Shoens (UCB) 12/7/78
  12.  */
  13.  
  14. #define    LENGTH    72        /* Max line length in output */
  15. #define    NOSTR    ((char *) 0)    /* Null string pointer for lint */
  16.  
  17. int    pfx;            /* Current leading blank count */
  18. int    lineno;            /* Current input line */
  19. int    mark;            /* Last place we saw a head line */
  20.  
  21. char    *calloc();        /* for lint . . . */
  22. char    *headnames[] = {"To", "Subj", "Cc", 0};
  23.  
  24. /*
  25.  * Drive the whole formatter by managing input files.  Also,
  26.  * cause initialization of the output stuff and flush it out
  27.  * at the end.
  28.  */
  29.  
  30. main(argc, argv)
  31.     char **argv;
  32. {
  33.     register FILE *fi;
  34.     register int errs = 0;
  35.  
  36.     setout();
  37.     lineno = 1;
  38.     mark = -10;
  39.     setbuf(stdout, calloc(1, BUFSIZ));
  40.     if (argc < 2) {
  41.         setbuf(stdin, calloc(1, BUFSIZ));
  42.         fmt(stdin);
  43.         oflush();
  44.         exit(0);
  45.     }
  46.     while (--argc) {
  47.         if ((fi = fopen(*++argv, "r")) == NULL) {
  48.             perror(*argv);
  49.             errs++;
  50.             continue;
  51.         }
  52.         fmt(fi);
  53.         fclose(fi);
  54.     }
  55.     oflush();
  56.     exit(errs);
  57. }
  58.  
  59. /*
  60.  * Read up characters from the passed input file, forming lines,
  61.  * doing ^H processing, expanding tabs, stripping trailing blanks,
  62.  * and sending each line down for analysis.
  63.  */
  64.  
  65. fmt(fi)
  66.     FILE *fi;
  67. {
  68.     char linebuf[BUFSIZ], canonb[BUFSIZ];
  69.     register char *cp, *cp2;
  70.     register int c, col;
  71.  
  72.     c = getc(fi);
  73.     while (c != EOF) {
  74.         
  75.         /*
  76.          * Collect a line, doing ^H processing.
  77.          * Leave tabs for now.
  78.          */
  79.  
  80.         cp = linebuf;
  81.         while (c != '\n' && c != EOF && cp-linebuf < BUFSIZ-1) {
  82.             if (c == '\b') {
  83.                 if (cp > linebuf)
  84.                     cp--;
  85.                 c = getc(fi);
  86.                 continue;
  87.             }
  88.             if ((c < ' ' || c >= 0177) && c != '\t') {
  89.                 c = getc(fi);
  90.                 continue;
  91.             }
  92.             *cp++ = c;
  93.             c = getc(fi);
  94.         }
  95.         *cp = '\0';
  96.  
  97.         /*
  98.          * Toss anything remaining on the input line.
  99.          */
  100.  
  101.         while (c != '\n' && c != EOF)
  102.             c = getc(fi);
  103.         
  104.         /*
  105.          * Expand tabs on the way to canonb.
  106.          */
  107.  
  108.         col = 0;
  109.         cp = linebuf;
  110.         cp2 = canonb;
  111.         while (c = *cp++) {
  112.             if (c != '\t') {
  113.                 col++;
  114.                 if (cp2-canonb < BUFSIZ-1)
  115.                     *cp2++ = c;
  116.                 continue;
  117.             }
  118.             do {
  119.                 if (cp2-canonb < BUFSIZ-1)
  120.                     *cp2++ = ' ';
  121.                 col++;
  122.             } while ((col & 07) != 0);
  123.         }
  124.  
  125.         /*
  126.          * Swipe trailing blanks from the line.
  127.          */
  128.  
  129.         for (cp2--; cp2 >= canonb && *cp2 == ' '; cp2--)
  130.             ;
  131.         *++cp2 = '\0';
  132.         prefix(canonb);
  133.         if (c != EOF)
  134.             c = getc(fi);
  135.     }
  136. }
  137.  
  138. /*
  139.  * Take a line devoid of tabs and other garbage and determine its
  140.  * blank prefix.  If the indent changes, call for a linebreak.
  141.  * If the input line is blank, echo the blank line on the output.
  142.  * Finally, if the line minus the prefix is a mail header, try to keep
  143.  * it on a line by itself.
  144.  */
  145.  
  146. prefix(line)
  147.     char line[];
  148. {
  149.     register char *cp, **hp;
  150.     register int np, h;
  151.  
  152.     if (strlen(line) == 0) {
  153.         oflush();
  154.         putchar('\n');
  155.         return;
  156.     }
  157.     for (cp = line; *cp == ' '; cp++)
  158.         ;
  159.     np = cp - line;
  160.  
  161.     /*
  162.      * The following horrible expression attempts to avoid linebreaks
  163.      * when the indent changes due to a paragraph.
  164.      */
  165.  
  166.     if (np != pfx && (np > pfx || abs(pfx-np) > 8))
  167.         oflush();
  168.     if (h = ishead(cp))
  169.         oflush(), mark = lineno;
  170.     if (lineno - mark < 3 && lineno - mark > 0)
  171.         for (hp = &headnames[0]; *hp != (char *) 0; hp++)
  172.             if (ispref(*hp, cp)) {
  173.                 h = 1;
  174.                 oflush();
  175.                 break;
  176.             }
  177.     if (!h && (h = (*cp == '.')))
  178.         oflush();
  179.     pfx = np;
  180.     split(cp);
  181.     if (h)
  182.         oflush();
  183.     lineno++;
  184. }
  185.  
  186. /*
  187.  * Split up the passed line into output "words" which are
  188.  * maximal strings of non-blanks with the blank separation
  189.  * attached at the end.  Pass these words along to the output
  190.  * line packer.
  191.  */
  192.  
  193. split(line)
  194.     char line[];
  195. {
  196.     register char *cp, *cp2;
  197.     char word[BUFSIZ];
  198.  
  199.     cp = line;
  200.     while (*cp) {
  201.         cp2 = word;
  202.         while (*cp && *cp != ' ')
  203.             *cp2++ = *cp++;
  204.  
  205.         /*
  206.          * Guarantee a space at end of line.
  207.          */
  208.  
  209.         if (*cp == '\0') {
  210.             *cp2++ = ' ';
  211.             if (any(cp[-1], ".:!"))
  212.                 *cp2++ = ' ';
  213.         }
  214.         while (*cp == ' ')
  215.             *cp2++ = *cp++;
  216.         *cp2 = '\0';
  217.         pack(word);
  218.     }
  219. }
  220.  
  221. /*
  222.  * Output section.
  223.  * Build up line images from the words passed in.  Prefix
  224.  * each line with correct number of blanks.  The buffer "outbuf"
  225.  * contains the current partial line image, including prefixed blanks.
  226.  * "outp" points to the next available space therein.  When outp is NOSTR,
  227.  * there ain't nothing in there yet.  At the bottom of this whole mess,
  228.  * leading tabs are reinserted.
  229.  */
  230.  
  231. char    outbuf[BUFSIZ];            /* Sandbagged output line image */
  232. char    *outp;                /* Pointer in above */
  233.  
  234. /*
  235.  * Initialize the output section.
  236.  */
  237.  
  238. setout()
  239. {
  240.     outp = NOSTR;
  241. }
  242.  
  243. /*
  244.  * Pack a word onto the output line.  If this is the beginning of
  245.  * the line, push on the appropriately-sized string of blanks first.
  246.  * If the word won't fit on the current line, flush and begin a new
  247.  * line.  If the word is too long to fit all by itself on a line,
  248.  * just give it its own and hope for the best.
  249.  */
  250.  
  251. pack(word)
  252.     char word[];
  253. {
  254.     register char *cp;
  255.     register int s, t;
  256.  
  257.     if (outp == NOSTR)
  258.         leadin();
  259.     t = strlen(word);
  260.     s = outp-outbuf;
  261.     if (t+s <= LENGTH) {
  262.         
  263.         /*
  264.          * In like flint!
  265.          */
  266.  
  267.         for (cp = word; *cp; *outp++ = *cp++)
  268.             ;
  269.         return;
  270.     }
  271.     if (s > pfx) {
  272.         oflush();
  273.         leadin();
  274.     }
  275.     for (cp = word; *cp; *outp++ = *cp++)
  276.         ;
  277. }
  278.  
  279. /*
  280.  * If there is anything on the current output line, send it on
  281.  * its way.  Set outp to NOSTR to indicate the absence of the current
  282.  * line prefix.
  283.  */
  284.  
  285. oflush()
  286. {
  287.     if (outp == NOSTR)
  288.         return;
  289.     *outp = '\0';
  290.     tabulate(outbuf);
  291.     outp = NOSTR;
  292. }
  293.  
  294. /*
  295.  * Take the passed line buffer, insert leading tabs where possible, and
  296.  * output on standard output (finally).
  297.  */
  298.  
  299. tabulate(line)
  300.     char line[];
  301. {
  302.     register char *cp, *cp2;
  303.     register int b, t;
  304.  
  305.     /*
  306.      * Toss trailing blanks in the output line.
  307.      */
  308.  
  309.     cp = line + strlen(line) - 1;
  310.     while (cp >= line && *cp == ' ')
  311.         cp--;
  312.     *++cp = '\0';
  313.     
  314.     /*
  315.      * Count the leading blank space and tabulate.
  316.      */
  317.  
  318.     for (cp = line; *cp == ' '; cp++)
  319.         ;
  320.     b = cp-line;
  321.     t = b >> 3;
  322.     b &= 07;
  323.     if (t > 0)
  324.         do
  325.             putc('\t', stdout);
  326.         while (--t);
  327.     if (b > 0)
  328.         do
  329.             putc(' ', stdout);
  330.         while (--b);
  331.     while (*cp)
  332.         putc(*cp++, stdout);
  333.     putc('\n', stdout);
  334. }
  335.  
  336. /*
  337.  * Initialize the output line with the appropriate number of
  338.  * leading blanks.
  339.  */
  340.  
  341. leadin()
  342. {
  343.     register int b;
  344.     register char *cp;
  345.  
  346.     for (b = 0, cp = outbuf; b < pfx; b++)
  347.         *cp++ = ' ';
  348.     outp = cp;
  349. }
  350.  
  351. /*
  352.  * Save a string in dynamic space.
  353.  * This little goodie is needed for
  354.  * a headline detector in head.c
  355.  */
  356.  
  357. char *
  358. savestr(str)
  359.     char str[];
  360. {
  361.     register char *top;
  362.  
  363.     top = calloc(strlen(str) + 1, 1);
  364.     if (top == NOSTR) {
  365.         fprintf(stderr, "fmt:  Ran out of memory\n");
  366.         exit(1);
  367.     }
  368.     copy(str, top);
  369.     return(top);
  370. }
  371.  
  372. /*
  373.  * Is s1 a prefix of s2??
  374.  */
  375.  
  376. ispref(s1, s2)
  377.     register char *s1, *s2;
  378. {
  379.  
  380.     while (*s1++ == *s2)
  381.         ;
  382.     return(*s1 == '\0');
  383. }
  384.