Annotation of 43BSD/contrib/spms/src/bin/plog/Plog.c, revision 1.1.1.1

1.1       root        1: static char *rcsid = "$Header$";
                      2: /*
                      3:  * plog - record, edit, print, sort progress of a project
                      4:  *
                      5:  * Author: Peter J. Nicklin
                      6:  */
                      7: #include <ctype.h>
                      8: #include <signal.h>
                      9: #include <stdio.h>
                     10: #include "bin.h"
                     11: #include "date.h"
                     12: #include "from.h"
                     13: #include "getarg.h"
                     14: #include "null.h"
                     15: #include "path.h"
                     16: #include "spms.h"
                     17: #include "system.h"
                     18: #include "yesno.h"
                     19: 
                     20: #define SUBJECT_MAX_FORWARD_LOOK 5     /* max no. of lines to read ahead */
                     21:                                        /* for "Subject: " */
                     22: #define TITLELENGTH            72      /* length of subject title */
                     23: /*
                     24:  * type of operation to be executed by plog
                     25:  */
                     26: #define APPENDLOG      1
                     27: #define EDITLOG                2
                     28: #define PRINTLOG       3
                     29: #define PRINTLOGTITLE  4
                     30: #define SORTLOG                5
                     31: 
                     32: char *PGN = "plog";                    /* program name */
                     33: int PRINT_TITLE = YES;                 /* print message titles? */
                     34: 
                     35: main(argc, argv)
                     36:        int argc;
                     37:        char **argv;
                     38: {
                     39:        extern int PPDEBUG;             /* project pathname debug flag */
                     40:        char command[PATHSIZE+8];       /* shell command buffer */
                     41:        char *cwp;                      /* current working project */
                     42:        char *getcwp();                 /* get current working project */
                     43:        char *pathcat();                /* pathname concatenation */
                     44:        char *pathname;                 /* regular pathname */
                     45:        char plog[PATHSIZE];            /* PROJECTLOG pathname */
                     46:        char *strcpy();                 /* string copy */
                     47:        FILE *ifp;                      /* input file stream */
                     48:        FILE *mustfopen();              /* must open file or die */
                     49:        FILE *ofp;                      /* output file stream */
                     50:        FILE *popen();                  /* open pipe */
                     51:        int action;                     /* what plog has to do */
                     52:        int decoderange();              /* decode message range */
                     53:        int naction = 0;                /* number of non-default actions */
                     54:        int range[2];                   /* range of messages to print */
                     55:        int sortlog();                  /* sort project log by date */
                     56:        int status = 0;                 /* exit status */
                     57:        int xppath();                   /* expand project pathname */
                     58:        PATH pathbuf;                   /* pathname struct buffer */
                     59:        void print();                   /* print PROJECTLOG */
                     60:        void print_head();              /* print PROJECTLOG message headings */
                     61: 
                     62:        action = APPENDLOG;
                     63:        range[0] = range[1] = 0;
                     64: 
                     65:        {
                     66:        register char *s;               /* option pointer */
                     67:        while (--argc > 0 && (**++argv == '-' || **argv == '+'))
                     68:                {
                     69:                if (**argv == '-')
                     70:                        {
                     71:                        for (s = argv[0]+1; *s != '\0'; s++)
                     72:                                switch (*s)
                     73:                                        {
                     74:                                        case 'D':
                     75:                                                PPDEBUG = YES;
                     76:                                                break;
                     77:                                        case 'e':
                     78:                                                action = EDITLOG;
                     79:                                                naction++;
                     80:                                                break;
                     81:                                        case 'h':
                     82:                                                PRINT_TITLE = NO;
                     83:                                                break;
                     84:                                        case 'p':
                     85:                                                action = PRINTLOG;
                     86:                                                naction++;
                     87:                                                if (decoderange(++s, range) == NO)
                     88:                                                        status = 1;
                     89:                                                goto endif;
                     90:                                        case 's':
                     91:                                                action = SORTLOG;
                     92:                                                naction++;
                     93:                                                break;
                     94:                                        default:
                     95:                                                warn("bad option -%c", *s);
                     96:                                                status = 1;
                     97:                                                goto endif;
                     98:                                        }
                     99:                        }
                    100:                else    {
                    101:                        for (s = argv[0]+1; *s != '\0'; s++)
                    102:                                switch (*s)
                    103:                                        {
                    104:                                        case 'h':
                    105:                                                action = PRINTLOGTITLE;
                    106:                                                naction++;
                    107:                                                break;
                    108:                                        default:
                    109:                                                warn("bad option +%c", *s);
                    110:                                                status = 1;
                    111:                                                goto endif;
                    112:                                        }
                    113:                        }
                    114:                endif: continue;
                    115:                }
                    116:        }
                    117:        if (status == 1 || argc > 1)
                    118:                {
                    119:                fatal("usage: plog [-e] [{+-}h] [-p[low[-high]]] [-s] [projectname]");
                    120:                }
                    121:        if (naction > 1)
                    122:                {
                    123:                fatal("choose only one of -e, -p, -s, or +h options");
                    124:                }
                    125:        if (argc == 0)
                    126:                {
                    127:                if ((cwp = getcwp()) == NULL)
                    128:                        fatal("no project environment");
                    129:                pathname = cwp;
                    130:                }
                    131:        else    {
                    132:                if (xppath(*argv, &pathbuf) == -1)
                    133:                        {
                    134:                        patherr(*argv);
                    135:                        exit(1);
                    136:                        }
                    137:                switch (pathbuf.p_mode & P_IFMT)
                    138:                        {
                    139:                        case P_IFNEW:
                    140:                        case P_IFREG:
                    141:                        case P_IFPDIR:
                    142:                                fatal("%s: no such project", *argv);
                    143:                        case P_IFHOME:
                    144:                        case P_IFPROOT:
                    145:                                pathname = pathbuf.p_path;
                    146:                                break;
                    147:                        }
                    148:                }
                    149:        pathcat(plog, pathname, PROJECTLOG);
                    150:        
                    151:        switch (action)
                    152:                {
                    153:                case APPENDLOG:
                    154:                        printf("Mailing to %s\n", plog);
                    155:                        sprintf(command, "Mail %s", plog);
                    156:                        status = system(command);
                    157:                        break;
                    158:                case EDITLOG:
                    159:                        printf("Editing %s\n", plog);
                    160:                        sprintf(command, "Mail -f %s", plog);
                    161:                        status = system(command);
                    162:                        break;
                    163:                case PRINTLOG:
                    164:                        ifp = mustfopen(plog, "r");
                    165:                        if (!isatty(fileno(stdout)) || (ofp = popen("more","w")) == NULL)
                    166:                                ofp = stdout;
                    167: 
                    168:                        print(ifp, ofp, range);
                    169: 
                    170:                        if (ofp != stdout)
                    171:                                pclose(ofp);
                    172:                        break;
                    173:                case PRINTLOGTITLE:
                    174:                        ifp = mustfopen(plog, "r");
                    175:                        if (!isatty(fileno(stdout)) || (ofp = popen("more","w")) == NULL)
                    176:                                ofp = stdout;
                    177: 
                    178:                        print_head(ifp, ofp);
                    179: 
                    180:                        if (ofp != stdout)
                    181:                                pclose(ofp);
                    182:                        break;
                    183:                case SORTLOG:
                    184:                        printf("Sorting %s\n", plog);
                    185:                        status = sortlog(plog);
                    186:                        break;
                    187:                }
                    188:        exit(status);
                    189: }
                    190: 
                    191: 
                    192: 
                    193: /*
                    194:  * decoderange() determines the range of message numbers to be printed.
                    195:  * Prints an error message and returns NO if syntax error, otherwise YES.
                    196:  */
                    197: decoderange(srange, range)
                    198:        char *srange;                   /* range string to decode */
                    199:        int range[];                    /* decoded message range */
                    200: {
                    201:        register char *s;               /* range string pointer */
                    202:        register int high = 0;          /* high end of message range */
                    203:        register int low = 0;           /* low end of message range */
                    204: 
                    205:        for (s = srange; isdigit(*s); s++)
                    206:                        low = 10*low + (*s - '0');
                    207:        if (*s == '-')
                    208:                for (s++; isdigit(*s); s++)
                    209:                                high = 10*high + (*s - '0');
                    210:        if (*s != '\0')
                    211:                {
                    212:                warn("%s: bad message range", srange);
                    213:                return(NO);
                    214:                }
                    215:        range[0] = low;
                    216:        range[1] = high;
                    217:        return(YES);
                    218: }
                    219: 
                    220: 
                    221: 
                    222: /*
                    223:  * print() copies input stream to output stream, printing a title at
                    224:  * the beginning of each log entry.
                    225:  */
                    226: void
                    227: print(ifp, ofp, range)
                    228:        register FILE *ifp;             /* input file stream */
                    229:        register FILE *ofp;             /* output file stream */
                    230:        int range[];                    /* range of messages to print */
                    231: {
                    232:        register int high;              /* top of range */
                    233:        register int low;               /* bottom of range */
                    234:        register int msgno;             /* current message number */
                    235:        char *fgets();                  /* get a line from input stream */
                    236:        char linebuf[BUFSIZ];           /* input line buffer */
                    237:        FROM *isfrom();                 /* is line a "From " line? */
                    238:        void print_title();             /* print message title */
                    239: 
                    240:        msgno = 0;
                    241:        low = range[0];
                    242:        high = range[1];
                    243: 
                    244:        while (fgets(linebuf, BUFSIZ, ifp) != NULL)
                    245:                if (isfrom(linebuf) != NULL)
                    246:                        {
                    247:                        msgno++;
                    248:                        if (msgno < low)
                    249:                                continue;
                    250:                        else if (msgno > high && high != 0)
                    251:                                break;
                    252:                        if (PRINT_TITLE == YES)
                    253:                                {
                    254:                                print_title(linebuf, ifp, ofp);
                    255:                                }
                    256:                        else    {
                    257:                                fputs(linebuf, ofp);
                    258:                                }
                    259:                        }
                    260:                else    {
                    261:                        if (msgno < low)
                    262:                                continue;
                    263:                        fputs(linebuf, ofp);
                    264:                        }
                    265: }
                    266: 
                    267: 
                    268: 
                    269: /*
                    270:  * print_head() prints the log entry headings only.
                    271:  */
                    272: void
                    273: print_head(ifp, ofp)
                    274:        register FILE *ifp;             /* input file stream */
                    275:        register FILE *ofp;             /* output file stream */
                    276: {
                    277:        register int msgno;             /* current message number */
                    278:        register char *sp;              /* subject field pointer */
                    279:        char *fgets();                  /* get a line from input stream */
                    280:        char linebuf[BUFSIZ];           /* input line buffer */
                    281:        char *skipword();               /* skip to next word */
                    282:        char *subject;                  /* beginning of subject field */
                    283:        FROM *fromline;                 /* "From " line struct */
                    284:        FROM *isfrom();                 /* is line a "From " line? */
                    285:        int i;                          /* read-ahead buffer counter */
                    286:        int strlen();                   /* string length */
                    287:        int strncmp();                  /* compare strings for n chars */
                    288: 
                    289:        msgno = 0;
                    290:        while (fgets(linebuf, BUFSIZ, ifp) != NULL)
                    291:                if ((fromline = isfrom(linebuf)) != NULL)
                    292:                        {
                    293:                        msgno++;
                    294:                        fprintf(ofp, "%3d %-10s %s", msgno, fromline->from, 
                    295:                                fromline->date);
                    296:                        for (i = 0; i < SUBJECT_MAX_FORWARD_LOOK; i++)
                    297:                                {
                    298:                                if (fgets(linebuf, BUFSIZ, ifp) == NULL)
                    299:                                        break;
                    300:                                if (strncmp("Subject: ", linebuf, 9) == 0)
                    301:                                        {
                    302:                                        sp = subject = skipword(linebuf);
                    303:                                        while (*sp != '\n' && *sp != '\0')
                    304:                                                sp++;
                    305:                                        *sp = '\0';
                    306:                                        fprintf(ofp, " \"%s\"", subject);
                    307:                                        }
                    308:                                else if (isfrom(linebuf) != NULL)
                    309:                                        {
                    310:                                        /* "From " line not welcome here */
                    311:                                        fseek(ifp, (long) -strlen(linebuf), 1);
                    312:                                        break;
                    313:                                        }
                    314:                                }
                    315:                        putc('\n', ofp);
                    316:                        }
                    317: }
                    318: 
                    319: 
                    320: 
                    321: /*
                    322:  * printsubject() pretty-prints a "Subject: " field.
                    323:  */
                    324: void
                    325: printsubject(linebuf, ofp)
                    326:        char *linebuf;                  /* line containing subject */
                    327:        register FILE *ofp;             /* output file stream */
                    328: {
                    329:        register int nblank;            /* number of blanks to pad title */
                    330:        char *skipword();               /* skip to next word */
                    331:        int strlen();                   /* string length */
                    332: 
                    333:        nblank = (TITLELENGTH - (strlen(linebuf) - 9)) / 2;
                    334:                                        /* length of "Subject: " = 9 chars */
                    335:        while (nblank-- > 0)
                    336:                putc(' ', ofp);
                    337:        fputs(skipword(linebuf), ofp);
                    338: }
                    339: 
                    340: 
                    341: 
                    342: /*
                    343:  * print_title() prints a subject title between two dashed lines. 
                    344:  * If a "Subject:" field cannot be found within SUBJECT_MAX_FORWARD_LOOK
                    345:  * lines of the "From" line, then, a single dash line is printed.
                    346:  */
                    347: #define PUTDASHLINE(fp)        {int i = TITLELENGTH; \
                    348:                        while (i-- > 0) putc('-', fp); putc('\n', fp);}
                    349: void
                    350: print_title(linebuf, ifp, ofp)
                    351:        char linebuf[];                 /* line buffer containing "From" */
                    352:        register FILE *ifp;             /* input file stream */
                    353:        register FILE *ofp;             /* output file stream */
                    354: {
                    355:        char *fgets();                  /* get a line from input stream */
                    356:        char frombuf[BUFSIZ];           /* "From " line buffer */
                    357:        char *strcpy();                 /* string copy */
                    358:        int i;                          /* read-ahead buffer counter */
                    359:        int strncmp();                  /* compare strings for n chars */
                    360:        long ftell();                   /* offset relative to file beginning */
                    361:        long markifp;                   /* mark position of file */
                    362:        void printsubject();            /* printprint "Subject: " field */
                    363: 
                    364:        PUTDASHLINE(ofp);
                    365: 
                    366:        markifp = ftell(ifp);
                    367:        strcpy(frombuf, linebuf);
                    368:        for (i = 0; i < SUBJECT_MAX_FORWARD_LOOK; i++)
                    369:                {
                    370:                if (fgets(linebuf, BUFSIZ, ifp) == NULL)
                    371:                        break;
                    372:                if (strncmp("Subject: ", linebuf, 9) == 0)
                    373:                        {
                    374:                        printsubject(linebuf, ofp);
                    375:                        PUTDASHLINE(ofp);
                    376:                        break;
                    377:                        }
                    378:                }
                    379:        fputs(frombuf, ofp);
                    380:        fseek(ifp, markifp, 0);
                    381: }
                    382: 
                    383: 
                    384: 
                    385: /*
                    386:  * sortlog() sorts the project log by date. Returns status 0 if
                    387:  * successful, otherwise 1.
                    388:  */
                    389: sortlog(logname)
                    390:        char *logname;                  /* name of project log file */
                    391: {
                    392:        register FILE *ifp;             /* input file stream */
                    393:        register int (*hstat)();        /* hangup status */
                    394:        register int (*istat)();        /* interrupt status */
                    395:        register int (*qstat)();        /* quit status */
                    396:        register long nc = 0;           /* number of characters read */
                    397:        char *fgets();                  /* get a line from input stream */
                    398:        char linebuf[BUFSIZ];           /* input line buffer */
                    399:        char *pathcat();                /* pathname concatenation */
                    400:        char *pathhead();               /* remove pathname tail */
                    401:        char *strcpy();                 /* string copy */
                    402:        FILE *mustfopen();              /* must open file or die */
                    403:        FILE *ofp;                      /* output file stream */
                    404:        FROM *from;                     /* broken down "From " line */
                    405:        FROM *initfrom();               /* initialize "From " pointer array */
                    406:        FROM *isfrom();                 /* is line a "From " line? */
                    407:        FROM *lastfrom;                 /* previous "From " line */
                    408:        FROM *savefrom();               /* save "From " lines */
                    409:        int len;                        /* length of input line */
                    410:        int outfrom();                  /* output "From " messages */
                    411:        int parsedate();                /* parse ctime(3) generated date */
                    412:        char sortlog[PATHSIZE];         /* temporary projectlog for sorting */
                    413:        int status = 0;                 /* return status */
                    414:        int strlen();                   /* string length */
                    415:        void sortfrom();                /* sort "From " lines */
                    416: 
                    417:        ifp = mustfopen(logname, "r");
                    418: 
                    419:        lastfrom = initfrom();
                    420: 
                    421:        for (;;)
                    422:                {
                    423:                if (fgets(linebuf, BUFSIZ, ifp) == NULL)
                    424:                        break;
                    425:                len = strlen(linebuf);
                    426:                nc += len;
                    427:                if ((from = isfrom(linebuf)) != NULL)
                    428:                        {
                    429:                        if (parsedate(from->date, &from->bdt) == NO)
                    430:                                {
                    431:                                warn("%s: bad date", from->date);
                    432:                                status = 1;
                    433:                                }
                    434:                        else    {
                    435:                                from->m_seek = nc - len;
                    436:                                lastfrom->m_len = from->m_seek - lastfrom->m_seek;
                    437:                                if ((lastfrom = savefrom(from)) == NULL)
                    438:                                        {
                    439:                                        warn("out of memory");
                    440:                                        return(1);
                    441:                                        }
                    442:                                }
                    443:                        }
                    444:                }
                    445:        lastfrom->m_len = nc - lastfrom->m_seek;
                    446:        if (status > 0)
                    447:                return(status);
                    448:        sortfrom();
                    449:        pathcat(sortlog, pathhead(strcpy(sortlog, logname)), "temp_log");
                    450:        if (FILEXIST(sortlog))
                    451:                {
                    452:                warn("%s sort in progress - try later", PROJECTLOG);
                    453:                return(1);
                    454:                }
                    455: 
                    456:        hstat = signal(SIGHUP, SIG_IGN);
                    457:        istat = signal(SIGINT, SIG_IGN);
                    458:        qstat = signal(SIGQUIT, SIG_IGN);
                    459: 
                    460:        ofp = mustfopen(sortlog, "w");
                    461:        if (outfrom(ifp, ofp) == YES)
                    462:                {
                    463:                fclose(ifp);
                    464:                fclose(ofp);
                    465:                RENAME(sortlog, logname);
                    466:                }
                    467:        else    {
                    468:                warn("write error in %s: sort failed", sortlog);
                    469:                fclose(ifp);
                    470:                fclose(ofp);
                    471:                unlink(sortlog);
                    472:                status = 1;
                    473:                }
                    474: 
                    475:        signal(SIGINT, hstat);
                    476:        signal(SIGINT, istat);
                    477:        signal(SIGQUIT, qstat);
                    478: 
                    479:        return(status);
                    480: }
                    481: 
                    482: 
                    483: 
                    484: /*
                    485:  * skipword() skips a liberal (blank, tab delimited) word and returns a
                    486:  * pointer to the next word.
                    487:  */
                    488: char *
                    489: skipword(bp)
                    490:        register char *bp;              /* buffer pointer */
                    491: {
                    492:        for (; *bp != '\0' && isspace(*bp); bp++)
                    493:                continue;
                    494:        for (; *bp != '\0' && !isspace(*bp); bp++)
                    495:                continue;
                    496:        for (; *bp != '\0' && isspace(*bp); bp++)
                    497:                continue;
                    498:        return(bp);
                    499: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.