[comp.sys.ibm.pc] ppc.c

evan@blake.acs.washington.edu (Not Evan) (01/31/89)

Due to overwhelming response to my earlier article concerning the public
domain C beautifier PPC.C, with comments, I have decided to post it.  I
will continue to accept requests for separately mailed copies.

By the way, I see a lot of mail paths like {ames,harvey,joe}!one!two!three
etc.  What are these, and what mail/send facility makes use of them?

Also, can anybody briefly explain the difference (if any) between mail and
uucp?

Thank you for your support.  Cheers!

++erw;


/* PPC.C - Pretty Printer for C
   Created from CB on SIMTEL20 by Richard Conn
   CB was heavily modified to create PPC */

#include <stdio.h>

#define TITLE "Pretty Printer for C, Beta Test Version 1.0"
#define MAXBRAC 20    /* maximum number of open braces allowed */
#define IFLEVEL 20    /* maximum number of nested IFs allowed */

int slevel[IFLEVEL];
int spflg[MAXBRAC][IFLEVEL];
int sind [MAXBRAC][IFLEVEL];
int siflev[IFLEVEL];
int sifflg[IFLEVEL];
int clevel = 0; /* Number of open braces */
int iflev = 0; /* Number of active IFs */
int ifflg = -1; /* Indicates if we have an active IF */
int level = 0;
int ind[IFLEVEL]; /* Indentation amount for a particular IF */
int pflg[IFLEVEL]; /* Number of characters to indent for a particular IF */
int eflg = 0; /* We are in an ELSE? */
int paren = 0; /* Number of open parentheses */
int tabcount = 4; /* Number of characters to indent */
char lchar;
char pchar;
int aflg = 0;
int stabs[MAXBRAC][IFLEVEL];
int qflg = 0;

/* The following are reserved words used for special processing */
char *wstr[] = {
    "typedef",
    "struct",
    "union",
    "int",
    "char",
    "unsigned",
    "long",
    "auto",
    NULL
};
char *wrsvwds[] = {
    "int",
    "char",
    "unsigned",
    "long",
    "auto",
    NULL
};
char *wif[] = {
    "if",
    NULL
};
char *welse[] = {
    "else",
    NULL
};
char *wfor[] = {
    "for",
    NULL
};
char *wds[] = {
    "case",
    "default",
    NULL
};

/* J is the index for the next character in the STRING buffer
   STRING is the buffer in which the output line is built */
int j = 0;
char string[400];

char cc;
int sflg = 1;
int bflg = 0;
int peek = -1;
int tabs = 0;
int lastchar = ' ';
int cin;

/* Input and output buffers */
FILE *inpbuf;
FILE *outbuf;

main(argc, argv)
int argc;
char *argv[];
{
    char bakfil[100]; /* name of current backup file */
    int filno; /* number of current file */
    int cont; /* local continuation flag */
    int ct; /* count of local open parens */
    int eflg; /* indicates we are in an ELSE */
    int i;

    if (argc == 1) {
        printf ("%s\n", TITLE);
        printf ("  Syntax: ppc [-i#] filename.ext [filename.ext ...]\n");
        printf ("  Options:\n");
        printf ("     -i#  Set indentation level for files\n");
        exit (0);
    }

    /* Zero indentation indicator and indent character count buffers */
    for (i=0; i<IFLEVEL; i++) { 
        ind[i] = 0; 
        pflg[i] = 0; 
    }

    /* Main Loop */
    for (filno=1; argv[filno]!=NULL; filno++) {

        /* Process next file (if not an option) */
        if (*argv[filno] != '-') {
            mkext (bakfil, argv[filno], "bak");
            unlink (bakfil);
            rename (argv[filno], bakfil);
            if ((inpbuf = fopen (bakfil, "r")) == NULL) {
                perror (bakfil);
                exit (1);
            }
            if ((outbuf = fopen (argv[filno], "w")) == NULL) {
                perror (argv[filno]);
                exit (1);
            }
            fprintf (stderr, "  Pretty Printing %s\n", argv[filno]);
            while ( (cin = getchr()) != EOF) {
                switch(cin) {
                case ' ':
                case '\t':
                    if (lookup(welse) == 1) {
                        gotelse ();
                        if (sflg == 0 || j > 0) string[j++] =cin;
                        putz ();
                        sflg = 0;
                        break;
                    }
                    if (sflg == 0 || j > 0) string[j++] =cin;
                    break;
                case '\n':
                    if ((eflg = lookup(welse)) == 1) gotelse();
                    putz();
                    fprintf (outbuf,"\n");
                    sflg = 1;
                    if (eflg == 1) {
                        pflg[level]++;
                        tabs++;
                    }
                    else
                        if (pchar == lchar)
                            aflg = 1;
                    break;
                case '{':
                    if (lookup(welse) == 1) gotelse();
                    siflev[clevel]= iflev;
                    sifflg[clevel]= ifflg;
                    iflev = ifflg = 0;
                    clevel++;
                    if (sflg == 1 && pflg[level] != 0) {
                        pflg[level]--;
                        tabs--;
                    }
                    string[j++] =cin;
                    putz ();
                    getnl ();
                    putz ();
                    fprintf (outbuf,"\n");
                    tabs++;
                    sflg = 1;
                    if (pflg[level] > 0) {
                        ind[level] = 1;
                        level++;
                        slevel[level] = clevel;
                    }
                    break;
                case '}':
                    clevel--;
                    if ((iflev = siflev[clevel]-1) < 0) iflev = 0;
                    ifflg = sifflg[clevel];
                    putz ();
                    tabs--;
                    ptabs ();
                    if ((peek = getchr()) == ';') {
                        fprintf (outbuf, "%c;", cin);
                        peek = -1;
                    }
                    else fprintf (outbuf,"%c", cin);
                    getnl ();
                    putz ();
                    fprintf (outbuf,"\n");
                    sflg = 1;
                    if (clevel < slevel[level]) if (level > 0) level--;
                    if (ind[level] != 0) {
                        tabs -= pflg[level];
                        pflg[level] =0;
                        ind[level] = 0;
                    }
                    break;
                case '"':
                case '\'':
                    string[j++] =cin;
                    while ((cc = getc(inpbuf)) !=cin) {
                        string[j++] =cc;
                        if (cc == '\\') string[j++] = getc(inpbuf);
                        if (cc == '\n') {
                            putz();
                            sflg = 1;
                        }
                    }
                    string[j++] =cc;
                    if (getnl() ==1) {
                        lchar = cc;
                        peek = '\n';
                    }
                    break;
                case ';':
                    string[j++] =cin;
                    putz ();
                    if (pflg[level] > 0 && ind[level] == 0) {
                        tabs -= pflg[level];
                        pflg[level] = 0;
                    }
                    getnl ();
                    putz ();
                    fprintf (outbuf,"\n");
                    sflg = 1;
                    if (iflev > 0)
                        if (ifflg == 1) {
                            iflev--;
                            ifflg = 0;
                        }
                        else iflev = 0;
                    break;
                case '\\':
                    string[j++] =cin;
                    string[j++] =getchr();
                    break;
                case '?':
                    qflg = 1;
                    string[j++] =cin;
                    break;
                case ':':
                    string[j++] =cin;
                    if (qflg == 1) {
                        qflg = 0;
                        break;
                    }
                    if (lookup(wrsvwds) == 1) break;
                    if (lookup(wds)== 0) {
                        sflg = 0;
                        putz ();
                    }
                    else {
                        tabs--;
                        putz ();
                        tabs++;
                    }
                    if ((peek = getchr()) == ';') {
                        fprintf (outbuf, ";");
                        peek = -1;
                    }
                    getnl ();
                    putz ();
                    fprintf (outbuf,"\n");
                    sflg = 1;
                    break;
                case '/':
                    string[j++] =cin;
                    if ((peek = getchr()) != '*') break;
                    string[j++] = peek;
                    peek = -1;
                    comment ();
                    break;
                case ')':
                    paren--;
                    string[j++] = cin;
                    putz ();
                    if (getnl() == 1) {
                        peek = '\n';
                        if (paren != 0) aflg = 1;
                        else if (tabs > 0) {
                            pflg[level]++;
                            tabs++;
                            ind[level] = 0;
                        }
                    }
                    break;
                case '#':
                    string[j++] =cin;
                    while ((cc = getc(inpbuf)) != '\n') string[j++] = cc;
                    string[j++] =cc;
                    sflg = 0;
                    putz ();
                    sflg = 1;
                    break;
                case '(':
                    string[j++] =cin;
                    paren++;
                    if (lookup(wfor) == 1) {
                        while ((cin = xgets()) != ';');
                        ct = 0;
                        cont = 1;
                        while (cont) {
                            while ((cin = xgets()) != ')') {
                                if (cin== '(') ct++;
                            }
                            if(ct != 0) {
                                ct--;
                            }
                            else cont = 0;
                        }
                        paren--;
                        putz ();
                        if (getnl() ==1) {
                            peek = '\n';
                            pflg[level]++;
                            tabs++;
                            ind[level] = 0;
                        }
                        break;
                    }
                    if (lookup(wif)== 1) {
                        putz ();
                        stabs[clevel][iflev] = tabs;
                        spflg[clevel][iflev] = pflg[level];
                        sind[clevel][iflev] = ind[level];
                        iflev++;
                        ifflg = 1;
                    }
                    break;
                default:
                    string[j++] = cin;
                    if (cin != ',') lchar = cin;
                    break;
                }
            }
            fclose (inpbuf);
            fclose (outbuf);
        }
        /* Process an option */
        else {
            option (&argv[filno][1]);
        }
    }
}

/* Process an option on the command line */
option (item)
char *item;
{
    switch (*item) {
    case 'i' :
    case 'I' :
        tabcount = atoi (++item);
        break;
    default :
        fprintf (stderr, "Invalid option in command line: %s\n", item);
        break;
    }
}

/*  Output leading indentation characters on the line */
ptabs()
{
    int i, k;

    for (i = 0; i < tabs; i++) { 
        for (k = 0; k<tabcount; k++)
            fprintf (outbuf, " "); 
    }
}

/* Return the next non-space or non-tab character and set PEEK to -1
   and PCHAR to LASTCHAR as side effects */
getchr()
{
    if (peek < 0 && lastchar != ' ' && lastchar != '\t') pchar = lastchar;
    if (peek == '\t') peek = ' ';
    if (peek == ' ' && peek == lastchar) {
        peek = -1;
    }
    while (peek < 0) {
        peek = getc (inpbuf);
        if (peek == EOF) break;
        if (peek == '\t') peek = ' ';
        if (peek == ' ' && peek == lastchar) peek = -1;
    }
    lastchar = peek;
    peek = -1;
    return (lastchar);
}

/* If the STRING buffer is not empty (J>0), output indentation tabs
   and the STRING buffer after appending a null to the STRING buffer
   and reset the STRING buffer to empty */
putz()
{
    int k;

    if (j > 0) {
        if (sflg != 0) {
            ptabs();
            sflg = 0;
            if (aflg == 1) {
                aflg = 0;
                if (tabs > 0) {
                    for (k = 0; k<tabcount; k++) fprintf (outbuf, " "); 
                }
            }
        }
        string[j] = '\0';
        fprintf (outbuf, "%s", string);
        j = 0;
    }
    else {
        if (sflg != 0) {
            sflg = 0;
            aflg = 0;
        }
    }
}

/* Return 1 if the first non-blank token in STRING is an element of
   the passed table */
lookup(tab)
char *tab[];
{
    char r;
    int l, kk, k, i;

    if (j < 1) return(0);
    kk = 0;
    while (string[kk] == ' ') kk++;
    for (i = 0; tab[i] != NULL; i++) {
        l = 0;
        for (k = kk; (r= tab[i][l++]) == string[k] && r !='\0'; k++);
        if (r == '\0' && (string[k] < 'a' || string[k] > 'z')) return(1);
    }
    return(0);
}

/* Return next character which is not an escaped character (leading
   back slash), a character constant, a string constant, or a new
   line (building the STRING buffer as we encounter these other items) */
xgets()
{
    int ch;

    while (1) {
        if ((ch = string[j++]= getchr()) == '\\') {
            string[j++] = getchr();
        }
        else {
            if (ch == '\'' || ch == '"') {
                while ((cc = string[j++] = getchr()) != ch) {
                    if (cc == '\\') string[j++] = getchr();
                }
            }
            else {
                if (ch == '\n') {
                    putz ();
                    aflg = 1;
                }
                else return(ch);
            }
        }
    }
}

/* We got an ELSE clause, so process if levels et al */
gotelse()
{
    tabs = stabs[clevel][iflev];
    pflg[level] = spflg[clevel][iflev];
    ind[level] = sind[clevel][iflev];
    ifflg = 1;
}

/* Skip to next non-space, non-tab, or non-comment character, returning
   1 if that character is a new line and 0 otherwise */
getnl()
{
    while ((peek = getchr()) == '\t' || peek == ' ') {
        string[j++] = peek;
        peek = -1;
    }
    if ((peek = getchr()) == '/') {
        peek = -1;
        if ((peek = getchr()) == '*') {
            string[j++] ='/';
            string[j++] ='*';
            peek = -1;
            comment();
        }
        else string[j++] = '/';
    }
    if ((peek = getchr()) == '\n') {
        peek = -1;
        return (1);
    }
    return (0);
}

/* Process comment, copying it into the output STRING buffer and allowing
   for nested comments */
comment()
{
    int repeat;
    int gotstar;

    repeat = 1;
    while (repeat) {
        while ((cin = string[j++] = getc(inpbuf)) != '*') {
            if (cin== '\n') {
                putz();
                sflg = 1;
            }
        }

        /* We got an asterisk */
        if (string[j-2]=='/') {
            fprintf (stderr, "Input has nested comments\n");
            comment ();
        }
        else {
            gotstar = 1;
            while (gotstar)
                if ((cin = string[j++] = getc(inpbuf)) != '*') gotstar = 0;
            if (cin == '/') repeat = 0;
            if (cin == '\n') { 
                putz (); 
                sflg = 1; 
            }
        }
    }
}

/* Build a new file name string (NEW) given the first part of an old
   file name string (OLD) and an extension (EXT) to be placed at the end of
   the new file name string */
mkext(new, old, ext)
char *new;
char *old;
char *ext;
{
    /* copy file name */
    while ((*old!='\0')&&(*old!='.')) *new++ = *old++;

    /* add a dot for the extension */
    *new++ = '.';

    /* copy extension */
    while (*ext!='\0') *new++ = *ext++;

    /* add string terminator */
    *new = '\0';
}