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: }

Defined functions

decoderange defined in line 197; used 2 times
main defined in line 35; never used
print defined in line 226; used 2 times
print_head defined in line 272; used 2 times
print_title defined in line 349; used 2 times
printsubject defined in line 324; used 2 times
skipword defined in line 488; used 7 times
sortlog defined in line 389; used 10 times

Defined variables

PGN defined in line 32; never used
PRINT_TITLE defined in line 33; used 2 times
rcsid defined in line 1; never used

Defined macros

APPENDLOG defined in line 26; used 1 times
  • in line 62
EDITLOG defined in line 27; used 1 times
  • in line 78
PRINTLOG defined in line 28; used 1 times
  • in line 85
PRINTLOGTITLE defined in line 29; used 1 times
PUTDASHLINE defined in line 347; used 2 times
SORTLOG defined in line 30; used 1 times
  • in line 91
SUBJECT_MAX_FORWARD_LOOK defined in line 20; used 2 times
TITLELENGTH defined in line 22; used 2 times
Last modified: 1985-07-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2406
Valid CSS Valid XHTML 1.0 Strict