home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / fmt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-02-01  |  7.5 KB  |  423 lines

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