home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / nov / mkov.c < prev    next >
C/C++ Source or Header  |  1994-10-17  |  9KB  |  407 lines

  1. /*
  2.  * mkov - turn news headers into news overview index lines
  3.  * See the file COPYRIGHT for the copyright notice.
  4.  *
  5.  * to add additional headers to the database, search for "step" and
  6.  * follow the simple directions.
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <fgetfln.h>
  16.  
  17. #define DEFXREF 50
  18.  
  19. #define    STREQ(a, b)    (*(a) == *(b) && strcmp((a), (b)) == 0)
  20.  
  21. /* imports */
  22. extern int optind;
  23. extern char *optarg;
  24. extern char *gethdr(), *strsave();
  25. extern FILE *efopen();
  26.  
  27. /* exports */
  28. char *progname = "";
  29. int debug;
  30.  
  31. /* forwards */
  32. char *str(), *parsehdrs();
  33.  
  34. /* privates */
  35. struct headers {
  36.     int    h_cnt;
  37.     /* common headers */
  38.     char *h_num;
  39.     char *h_from;
  40.     char *h_subj;
  41.     char *h_date;
  42.     char *h_msgid;
  43.     char *h_refs;
  44.     char *h_bytes;
  45.     char *h_lines;
  46.     /* used internally; not normally put in the database */
  47.     char *h_xref;
  48.     char *h_intxref;
  49.     /* extension headers */
  50.     /* step 1 of 4: add new field definition before this line */
  51. };
  52. static int articles = 0;    /* if true, read article files */
  53. static time_t oldtime = 0;
  54. static int prgrps = 0;    /* if true, print group name(s) first, even under -a */
  55. static int readnames = 0;    /* if true, read filenames from stdin */
  56.  
  57. /*
  58.  * main - parse arguments and handle options
  59.  */
  60. main(argc, argv)
  61. int argc;
  62. char *argv[];
  63. {
  64.     int c, errflg = 0;
  65.     char *older = NULL;
  66.  
  67.     if (argc > 0)
  68.         progname = argv[0];
  69.     while ((c = getopt(argc, argv, "adino:")) != EOF)
  70.         switch (c) {
  71.         case 'a':
  72.             articles++;
  73.             break;
  74.         case 'd':
  75.             ++debug;
  76.             break;
  77.         case 'i':
  78.             readnames++;
  79.             break;
  80.         case 'n':
  81.             prgrps++;
  82.             break;
  83.         case 'o':
  84.             older = optarg;
  85.             break;
  86.         default:
  87.             errflg++;
  88.             break;
  89.         }
  90.     if (errflg || (readnames && optind < argc)) {
  91.         (void) fprintf(stderr, "usage: %s [-adin] [-o file] [file]...\n",
  92.             progname);
  93.         exit(2);
  94.     }
  95.  
  96.     if (older != NULL) {
  97.         struct stat statb;
  98.  
  99.         if (stat(older, &statb) < 0)
  100.             error("can't stat %s", older);
  101.         oldtime = statb.st_mtime;
  102.     }
  103.  
  104.     if (readnames) {
  105.         char *name;
  106.  
  107.         while ((name = fgetline(stdin, (size_t *)NULL)) != NULL) {
  108.             if (!(articles && !artname(name))) {
  109.                 FILE *in;
  110.  
  111.                 in = fopen(name, "r");
  112.                 if (in == NULL)
  113.                     warning("can't open `%s'", name);
  114.                 else {
  115.                     process(in, name);
  116.                     (void) fclose(in);
  117.                 }
  118.             }
  119.         }
  120.     } else if (optind >= argc)
  121.         process(stdin, "stdin");
  122.     else
  123.         for (; optind < argc; optind++) {
  124.             char *name = argv[optind];
  125.  
  126.             if (STREQ(name, "-"))
  127.                 process(stdin, "-");
  128.             else if (!(articles && !artname(name))) {
  129.                 FILE *in;
  130.  
  131.                 in = fopen(name, "r");
  132.                 if (in == NULL)
  133.                     warning("can't open `%s'", name);
  134.                 else {
  135.                     process(in, name);
  136.                     (void) fclose(in);
  137.                 }
  138.             }
  139.         }
  140.     exit(0);
  141. }
  142.  
  143. int
  144. artname(s)
  145. char *s;
  146. {
  147.     register char *base = strrchr(s, '/');
  148.  
  149.     if (base == NULL)
  150.         base = s;
  151.     else
  152.         base++;
  153.     return isascii(*base) && isdigit(*base);
  154. }
  155.  
  156. /*
  157.  * process - process input file
  158.  */
  159. process(in, inname)
  160. FILE *in;
  161. char *inname;
  162. {
  163.     register char *hdr;
  164.     char *base = strrchr(inname, '/'), *artnumstr;
  165.     char bytes[25];
  166.     struct headers hdrs;
  167.  
  168.     if (base == NULL)
  169.         base = inname;
  170.     else
  171.         base++;
  172.     if (articles) {
  173.         struct stat statb;
  174.  
  175.         if (fstat(fileno(in), &statb) < 0)
  176.             error("fstat of %s failed", inname);
  177.         if ((statb.st_mode&S_IFMT) == S_IFDIR ||
  178.             (oldtime > 0 && statb.st_mtime > oldtime))
  179.             return;        /* ignore directories and new files */
  180.         artnumstr = base;
  181.         (void) sprintf(bytes, "%ld", (long)statb.st_size);
  182.     }
  183.     do {
  184.         hdr = parsehdrs(in, &hdrs);    /* hdr is malloced; don't free */
  185.         if (hdrs.h_cnt == 0) {        /* no valid headers parsed? */
  186.             if (hdr == NULL)    /* EOF? */
  187.                 break;
  188.             else if (*hdr == '\n')    /* blank line? */
  189.                 continue;    /* ignore it and try again */
  190.             else {
  191.                 fprintf(stderr, "%s: garbage input: %s",
  192.                     progname, hdr);
  193.                 continue;
  194.             }
  195.         }
  196.         /* print index line from headers */
  197.         if (articles) {
  198.             hdrs.h_num = strsave(artnumstr);
  199.             hdrs.h_bytes = strsave(bytes);
  200.             if (!prgrps)
  201.                 prhdrs(&hdrs);
  202.             else if (hdrs.h_intxref == NULL)
  203.                 fprintf(stderr, "%s: no Xref: header in %s\n",
  204.                     progname, hdrs.h_msgid);
  205.             else
  206.                 prstridx(&hdrs);
  207.         } else if (hdrs.h_intxref == NULL)
  208.             fprintf(stderr, "%s: no Xref: header in %s\n", progname,
  209.                 hdrs.h_msgid);
  210.         else                /* reading header stream */
  211.             prstridx(&hdrs);
  212.  
  213.         freehdrs(&hdrs);
  214.     } while (!articles && hdr != NULL);
  215. }
  216.  
  217. char *                    /* NULL at EOF, or malloced, don't free */
  218. parsehdrs(in, hdrp)
  219. FILE *in;
  220. register struct headers *hdrp;
  221. {
  222.     register char *hdr;
  223.     int ishdr = 0;
  224.     long lim;
  225.     static struct headers zhdrs;
  226.  
  227.     *hdrp = zhdrs;
  228.     while ((lim = -1, hdr = gethdr(in, &lim, &ishdr)) != NULL && ishdr) {
  229.         register char *kwp;
  230.         char *colon = strchr(hdr, ':');
  231.  
  232.         if (colon == NULL)
  233.             break;            /* can't happen */
  234.         *colon = '\0';
  235.  
  236.         /* canonicalise case */
  237.         for (kwp = hdr; *kwp != '\0'; kwp++)
  238.             if (isascii(*kwp) && isupper(*kwp))
  239.                 *kwp = tolower(*kwp);
  240.         /* record initial address for later freeing */
  241.         if (STREQ(hdr, "number"))
  242.             hdrp->h_num = str(colon+1, 0);
  243.         else if (STREQ(hdr, "from"))
  244.             hdrp->h_from = str(colon+1, 0);
  245.         else if (STREQ(hdr, "subject"))
  246.             hdrp->h_subj = str(colon+1, 0);
  247.         else if (STREQ(hdr, "date"))
  248.             hdrp->h_date = str(colon+1, 0);
  249.         else if (STREQ(hdr, "message-id"))
  250.             hdrp->h_msgid = str(colon+1, 0);
  251.         else if (STREQ(hdr, "references"))
  252.             hdrp->h_refs = str(colon+1, 0);
  253.         else if (STREQ(hdr, "bytes"))
  254.             hdrp->h_bytes = str(colon+1, 0);
  255.         else if (STREQ(hdr, "lines"))
  256.             hdrp->h_lines = str(colon+1, 0);
  257.         /* step 2 of 4: add new header recognition before this line */
  258.         else if (STREQ(hdr, "xref")) {
  259.             hdrp->h_xref = str(colon+1, 0);
  260.             hdrp->h_intxref = str(colon+1, 1);
  261.         }
  262.         hdrp->h_cnt++;
  263.         *colon = ':';
  264.         /* must not free hdr; gethdr does that internally */
  265.     }
  266.     return hdr;
  267. }
  268.  
  269. prfld(fld)
  270. register char *fld;
  271. {
  272.     if (fld != NULL)
  273.         (void) fputs(fld, stdout);
  274. }
  275.  
  276. putfld(fld)
  277. char *fld;
  278. {
  279.     (void) putchar('\t');
  280.     prfld(fld);
  281. }
  282.  
  283. putextfld(keywd, extfld)
  284. char *keywd, *extfld;
  285. {
  286.     (void) putchar('\t');
  287.     if (extfld != NULL) {
  288.         (void) fputs(keywd, stdout);
  289.         (void) fputs(": ", stdout);
  290.         (void) fputs(extfld, stdout);
  291.     }
  292. }
  293.  
  294. prhdrs(hdrp)
  295. register struct headers *hdrp;
  296. {
  297.     register char *p;
  298.  
  299.     prfld(hdrp->h_num);
  300.     putfld(hdrp->h_subj);
  301.     putfld(hdrp->h_from);
  302.     putfld(hdrp->h_date);
  303.     putfld(hdrp->h_msgid);
  304.     putfld(hdrp->h_refs);
  305.     putfld(hdrp->h_bytes);
  306.     putfld(hdrp->h_lines);
  307.     /* put Xref in only if there is more than one locator in it */
  308.     if (hdrp->h_xref != NULL)
  309.         p = strchr(hdrp->h_xref, ' ');    /* p -> space after relayer */
  310.     else
  311.         p = NULL;
  312.     if (p != NULL)
  313.         p = strchr(p, ':');    /* p -> colon in first location */
  314.     if (p != NULL)
  315.         p = strchr(p+1, ':');    /* p -> colon in second location */
  316.     if (p != NULL)            /* at least two locations! */
  317.         putextfld("xref", hdrp->h_xref);
  318.     /* step 3 of 4: add new header output before this line */
  319.     (void) putchar('\n');
  320. }
  321.  
  322. prstridx(hdrp)        /* print index lines from header stream */
  323. register struct headers *hdrp;
  324. {
  325.     register int i, nxrefs;
  326.     char *xref[DEFXREF];
  327.     char **xrefp = xref;
  328.  
  329.     nxrefs = awksplit(hdrp->h_intxref, &xrefp, DEFXREF, " ");
  330.     if (xrefp == NULL)
  331.         fprintf(stderr, "%s: out of memory\n", progname);
  332.     else if (nxrefs < 2)
  333.         fprintf(stderr, "%s: too few Xref:s\n", progname);
  334.     else {
  335.         /* start at 1 to skip site name */
  336.         for (i = 1; i < nxrefs; i++) {
  337.             char *colon = strchr(xrefp[i], ':');
  338.  
  339.             if (colon == NULL)
  340.                 fprintf(stderr, "%s: bad Xref %s in %s\n",
  341.                     progname, xrefp[i], hdrp->h_msgid);
  342.             else {
  343.                 *colon = '\0';
  344.                 printf("%s\t", xrefp[i]);
  345.                 hdrp->h_num = strsave(colon+1);
  346.                 prhdrs(hdrp);
  347.                 *colon = ':';
  348.             }
  349.         }
  350.         if (xrefp != xref)
  351.             free((char *)xrefp);
  352.     }
  353. }
  354.  
  355. nnfree(s)
  356. register char *s;
  357. {
  358.     if (s != NULL)
  359.         free(s);
  360. }
  361.  
  362. freehdrs(hdrp)
  363. register struct headers *hdrp;
  364. {
  365.     nnfree(hdrp->h_num);
  366.     nnfree(hdrp->h_subj);
  367.     nnfree(hdrp->h_from);
  368.     nnfree(hdrp->h_date);
  369.     nnfree(hdrp->h_msgid);
  370.     nnfree(hdrp->h_refs);
  371.     nnfree(hdrp->h_bytes);
  372.     nnfree(hdrp->h_lines);
  373.     nnfree(hdrp->h_xref);
  374.     /* don't free h_intxref here; it's special */
  375.     /* step 4 of 4: free new header before this line */
  376. }
  377.  
  378. char *                    /* malloced */
  379. str(hdrln, xref)        /* strip leading & trailing whitespace */
  380. char *hdrln;
  381. register int xref;
  382. {
  383.     register char *p, *kwp, *copy;
  384.     register char c;
  385.     register int inspace = 0;
  386.  
  387.     for (p = hdrln; *p != '\0' && isascii(*p) && isspace(*p); p++)
  388.         ;        /* skip leading whitespace */
  389.     copy = strsave(p);
  390.     p = NULL;
  391.     for (kwp = copy; (c = *kwp) != '\0'; kwp++) {
  392.         if (c == '\t' || c == '\n')
  393.             *kwp = c = ' ';    /* keep format sane */
  394.         else if (xref && c == '.')
  395.             *kwp = c = '/';    /* group -> dir. */
  396.         if (!inspace && c == ' ') {
  397.             inspace++;
  398.             p = kwp;
  399.         }
  400.         if (c != ' ')
  401.             inspace = 0;
  402.     }
  403.     if (p != NULL)
  404.         *p = '\0';    /* trim trailing whitespace */
  405.     return copy;
  406. }
  407.