home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / newscnt / newscnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  10.9 KB  |  438 lines

  1. /* newscnt -- a program to enumerate unread net.news articles     *
  2.  *                                                                *
  3.  *   Glen A. Taylor (AT&T-IS)         May 1986                    *
  4.  *                                                                *
  5.  * Added the code inside the BSD and USE_GETOPT #ifdef's      *
  6.  *   Rich $alz (Mirror Systems)       June 1986                   *
  7.  *                                                                */
  8.  
  9.  
  10. static char sccsid[] = "@(#)newscnt.c    1.2";
  11.  
  12. #define BSD
  13. #define DEBUG
  14.  
  15. #include <stdio.h>
  16. #ifdef BSD
  17. #include <strings.h>
  18. char *strtok();
  19. #else
  20. #include <string.h>
  21. #endif
  22. #include <pwd.h>
  23. #include <ctype.h>
  24.  
  25. #define FALSE    0
  26. #define TRUE    1
  27. #define SILENT  4
  28. #define TERSE   2
  29. #define ALL     1
  30. #define ERROR   -1
  31. #define NEWS    0
  32. #define NONEWS  1
  33. #define MAXLENG 512
  34. #define MAXGRPS 128
  35. #define ACTIVE  "/usr/lib/news/active"
  36. #define NEWSRC  ".newsrc"
  37. #ifdef BSD
  38. #define USER_NAME "USER"
  39. #else
  40. #define USER_NAME    "LOGNAME"
  41. #endif
  42.  
  43. struct grp {
  44.     char *name;   /* news group name */
  45.     long  lowest; /* lowest article number */
  46.     long  highest; /* highest article number */
  47.     int   done; /* to indicate this element has been processed */
  48.     struct grp *ptr; /* ptr. to next element */
  49. };
  50.  
  51. typedef struct grp *GRPTR;
  52.  
  53. char *namevec[MAXGRPS]; /* array of newsgroup name strings */
  54.  
  55. main(argc,argv)
  56. int argc;
  57. char **argv;
  58. {
  59.  
  60.     char *alt_newsrc,  **newsgrps, *malloc();
  61.     int silent, terse, all, flags, fflag, nflag, xflag, nr_newsgrps;
  62.     FILE *fpnewsrc, *fpactive;
  63.     int count = 0;
  64.     GRPTR listhead = NULL;
  65.  
  66.     /* Parse arguments and establish working parameters */
  67. #ifdef    USE_GETOPT
  68.     {
  69.     char c;
  70.     extern char *optarg;
  71.     extern int optind;
  72.  
  73.     nr_newsgrps = silent = terse = all = xflag = fflag = nflag = flags = 0;
  74.     while ((c = getopt(argc, argv, "staxf:n:")) != EOF)
  75.         switch (c) {
  76.         default:
  77. Usage:
  78.             fprintf(stderr,
  79.                "usage: %s [-{sta}] [-x] [-f alt_.newsrc] -n newsgrp...",
  80.                argv[0]);
  81.             exit(1);
  82.         case 's': silent = 1; break;
  83.         case 't': terse = 1; break;
  84.         case 'a': all = 1; break;
  85.         case 'x': xflag = 1; break;
  86.         case 'f': fflag = 1; alt_newsrc = optarg; break;
  87.         case 'n': nflag = 1; nr_newsgrps += addgrp(optarg); break;
  88.         }
  89.     if (silent + terse + all > 1)
  90.         goto Usage;
  91.     for (argv += optind; *argv; argv++)
  92.         nr_newsgrps += addgrp(argv);
  93.     }
  94. #else    /* !USE_GETOPT */
  95.     if (!scanargs(argc,argv, "% sta%- x%- f%-alt_.newsrc!s n%-newsgrp!*s",
  96.      &flags, &xflag, &fflag, &alt_newsrc, &nflag, &nr_newsgrps, &newsgrps))
  97.      exit(1);
  98.     silent = flags & SILENT;
  99.     terse  = flags & TERSE;
  100.     all    = flags & ALL;
  101. #endif    /* USE_GETOPT */
  102.  
  103.     /* Open the .newsrc file */
  104.     if (fflag) { /* use the file name the user supplied */
  105.     fpnewsrc = fopen(alt_newsrc,"r");
  106.     }
  107.     else { /* determine the user's .newsrc file and open */
  108.     {
  109.         char *fname[MAXLENG];
  110.         char *uname, *getenv();
  111.         struct passwd *passptr, *getpwnam();
  112.  
  113.         uname = getenv(USER_NAME); /* get user's login name */
  114.         passptr = getpwnam(uname); /* get user's home dir */
  115.         /* construct .newsrc path */
  116.         strcpy(fname, passptr -> pw_dir);
  117.         strcat(fname, "/");
  118.         strcat(fname, NEWSRC);
  119.  
  120.         fpnewsrc = fopen(fname,"r");
  121.     }
  122.     }
  123.  
  124.     /* Derive array of newsgroup names to search for */
  125.     if (!nflag) getgrps(fpnewsrc, &nr_newsgrps, &newsgrps);
  126.  
  127. #ifdef DEBUG
  128.     { int i;
  129.       printf("Number of newsgroups = %d\n", nr_newsgrps);
  130.       for (i = 0; i < nr_newsgrps; i++) printf("%s\n", newsgrps[i]);
  131.     }
  132. #endif
  133.  
  134.     if (nr_newsgrps == 0) exit (ERROR); /* can't do anything! */
  135.  
  136.     /* Open the ACTIVE newsgroup file */
  137.     if ((fpactive = fopen(ACTIVE, "r"))==NULL)
  138.     exit(ERROR); /* cannot proceed w/o ACTIVE file */
  139.  
  140.     /* Go through the ACTIVE file and make linked list of all 
  141.        newsgroups matching elements of the "newsgrps" array   */
  142.     {
  143.     char gname[MAXLENG];   /* tmp to hold active group name */
  144.     long low, high;  /* tmps to hold active group low & high numbers */
  145.     int i, j;
  146.     char *sp, junk[10];
  147.     GRPTR current, next;
  148.  
  149.     while (fscanf(fpactive,"%s %ld %ld %s\n", gname, &high, &low, junk)
  150.         != EOF) { /* read the entire ACTIVE file */
  151.  
  152.         /* Compare gname to every name in newsgrps */
  153.         for (i=0; i < nr_newsgrps; i++) {
  154.         sp = newsgrps[i];
  155.         j = strlen(sp);
  156.         /* check for a group to be explicitly skipped */
  157.         if (*sp == '!') { 
  158.             sp++;
  159.             if (strncmp(gname,sp,j-1) == 0) break;
  160.         }
  161.         /* otherwise check for a positive match */
  162.         else if (strncmp(gname,sp,j) == 0) {
  163.         /* got a matching group so allocate new list element */
  164.             next = (struct grp *) malloc(sizeof (struct grp));
  165.  
  166.             if (!listhead) {/* first element */
  167.             listhead = next;
  168.             current = next;
  169.             }
  170.             else {
  171.             current -> ptr = next; /* link on this element */
  172.             current = next;
  173.             }
  174.             /* fill in the list element structure */
  175.             j = strlen(gname) + 1; /* get length of group name */
  176.             current -> name = strcpy(malloc(j), gname);
  177.             current -> lowest = low;
  178.             current -> highest = high;
  179.             current -> done = FALSE;
  180.             current -> ptr = NULL;
  181.  
  182.             /* terminate inner loop -- proceed to next group */
  183.             break;
  184.         }
  185.         }
  186.     }
  187.     }
  188.  
  189. #ifdef DEBUG
  190.     {
  191.     GRPTR lptr;
  192.     printf("\nList of relevant active newsgroups:\n");
  193.     lptr = listhead;
  194.     while (lptr != NULL) {
  195.         printf("%s %d %d\n",lptr->name,lptr->highest,lptr->lowest);
  196.         lptr = lptr->ptr;
  197.     }
  198.     }
  199. #endif
  200.  
  201.     /* Work down the linked list and compare to .newsrc entries */
  202.     rewind(fpnewsrc);
  203.     {
  204.     GRPTR next;
  205.     char line[MAXLENG], *gname, *range;
  206.     int ignore, cnt;
  207.  
  208.     while(fgets(line, MAXLENG, fpnewsrc) != NULL){
  209.         gname = line; /* name starts in first char position */
  210.         range = line; /* find the "range" list */
  211.         while (*range != ':' && *range != '!' && *range != '\0')
  212.         range++; /* : and ! are the two legal name delimiters */
  213.         ignore = *range == '!' ? TRUE : FALSE; /* do we ignore? */
  214.         *range++ = '\0'; /* delimit gname from range */
  215.  
  216.         /* Search the list for this newsgroup */
  217.         next = listhead;
  218.         while (next != NULL) {
  219.         if (strcmp(gname,next -> name) == 0) {/* Found it */
  220.             if (!ignore) {
  221.                 cnt = ckrange(next, range, xflag);
  222.             count = count + cnt;
  223.             if (all && cnt) printf("%s: %d articles\n",gname,cnt);
  224.             }
  225.             next -> done = TRUE;
  226.             break;
  227.         }
  228.         next = next -> ptr;
  229.         }
  230.     }
  231.     /* go through list one more time and get those that aren't "done" */
  232.     next = listhead;
  233.     while (next != NULL) {
  234.         if (! next -> done) {
  235.         cnt = next -> highest - next -> lowest;
  236.         if (cnt < 0) cnt = 0;
  237.         count = count + cnt;
  238.         /* print the nonzero entries if "all" were requested */
  239.         if (all && cnt) printf("%s: %d articles\n",next->name,cnt);
  240.         }
  241.         next = next -> ptr;
  242.     }
  243.     }
  244.  
  245.     /* Print final total */
  246.     if (silent) exit( count? NEWS : NONEWS);
  247.     if (terse) printf("%d\n", count);
  248.     else if (count) printf("%d news articles.\n",count);
  249.     else printf("No news.\n");
  250.     exit(count? NEWS : NONEWS);
  251. }
  252.  
  253. #ifdef    USE_GETOPT
  254. /* addgrp -- add a group list to the namevec global array.
  255.          returns count of groups added.            */
  256. addgrp(p)
  257. char *p;
  258. {
  259.     static char SEPARATORS[] = " \t\n,";
  260.     static int cnt;
  261.     char *ptr;
  262.     int i;
  263.  
  264.     ptr = strtok(p, SEPARATORS);
  265.     for (i = 0; ptr = strtok(NULL, SEPARATORS); i++)
  266.     namevec[cnt++] = strcpy(malloc(strlen(ptr) + 1), ptr);
  267.     return(i);
  268. }
  269. #endif    /* USE_GETOPT */
  270.  
  271.  
  272. /* getgrps -- reads the .newsrc file, finds the "option -n ... " news
  273.           group list, and copies news groups into an array of
  274.           strings.                                                */
  275. getgrps(fp, num, names)
  276. FILE *fp;
  277. int *num;
  278. char ***names;
  279. {
  280.     char line[MAXLENG], *ptr;
  281.     int optflag = FALSE, nflag = FALSE;
  282.  
  283.     *names = namevec;
  284.     *num = 0;
  285.     while (fgets(line,MAXLENG,fp) != NULL ) {
  286.     if (!optflag && strncmp(line,"option",6) == 0) { 
  287.         /* found an option line */
  288.         optflag = TRUE;
  289.         nflag = FALSE;
  290.         ptr = strtok(line," \t\n");
  291.         ptr = strtok(NULL," \t\n"); /* skip "option" */
  292.     }
  293.     else if (optflag && isspace(line[0])) {
  294.         /* found a continuation line */
  295.         ptr = strtok(line," \t\n");
  296.     }
  297.     else {
  298.         optflag = FALSE;
  299.         nflag = FALSE;
  300.     }
  301.  
  302.     /* Parse the options line */
  303.     if (optflag) {
  304.         while (!nflag && ptr != NULL) {
  305.         if (strcmp(ptr,"-n") == 0) {
  306.             nflag = TRUE;
  307.             ptr = strtok(NULL, " \t\n"); /* consume "-n" */
  308.             break;
  309.         }
  310.         ptr = strtok(NULL, " \t\n"); /* get first news group */
  311.         }
  312.         while (nflag && ptr != NULL) {
  313.         /* copy this news group into "newsgrps" */
  314.         namevec[*num] = strcpy(malloc(strlen(ptr)+1), ptr);
  315.         *num += 1;
  316.         ptr = strtok(NULL, " \t\n");
  317.         }
  318.     }
  319.     }
  320. }
  321.  
  322. /* ckrange -- compare a range specification against a high count / low
  323.           count and return the number of unread articles          */
  324. int
  325. ckrange(ptr, range, flag)
  326. GRPTR ptr;
  327. char *range;
  328. int flag;
  329. {
  330.     long low, high, nxthi, nxtlo;
  331.     int i, extent, count;
  332.     char *bitmap, *nextseg(), *rp;
  333.  
  334. #ifdef DEBUG
  335.     printf("<*> ckrange: \n\tname -- %s\n\thigh = %d\n\tlow = %d\n",
  336.     ptr->name, ptr->highest, ptr->lowest);
  337.     printf("\trange -- %s\n", range);
  338. #endif
  339.  
  340.     /* get low and high values for the newsgroup */
  341.     low = ptr -> lowest;
  342.     high = ptr -> highest;
  343.     if (low > high) return (0); /* this one is screwy! */
  344.  
  345.  
  346.     if (flag) { /* ignore range info */
  347.     count = high - low;
  348.     if (count < 0 ) count = 0;
  349.     return (count);
  350.     }
  351.  
  352.     /* set up a bitmap to do the computation */
  353.     extent = high - low + 1;
  354.     if (extent <= 0) return (0);
  355.     bitmap = malloc(extent);
  356.     if (bitmap == NULL) exit(ERROR);
  357.     for (i=0; i < extent; i++) bitmap[i] = '*'; /* init. bitmap */
  358.  
  359.     /* set bits (bytes, actually) for each read article */
  360.     rp = range;
  361.     while ((rp = nextseg(&nxthi,&nxtlo,rp)) != NULL) {
  362. #ifdef DEBUG
  363.     printf("<*> nexthi = %d, nextlo = %d\nnext seg = `%s'\n",
  364.     nxthi, nxtlo, rp);
  365. #endif
  366.  
  367.     /* check that the ones read intersect the ones avail */
  368.     if (nxthi < low || nxtlo > high) continue;
  369.  
  370.     /* adjust the range markers to the intersection */
  371.     nxthi = (high > nxthi) ? nxthi : high;
  372.     nxtlo = (low < nxtlo) ? nxtlo : low;
  373.  
  374.     /* mark the articles that were read */
  375.     if (nxtlo == nxthi) bitmap[nxtlo-low] = ' ';
  376.     else for (i=nxtlo-low; i <= nxthi-low; i++) bitmap[i] = ' ';
  377.     }
  378.  
  379.     /* count the set bits & go home */
  380.     count = 0;
  381.     for (i=0; i < extent; i++) if (bitmap[i] == '*') count++;
  382.     free(bitmap);
  383.     return (count);
  384. }
  385.  
  386. char *
  387. nextseg(high, low, str)
  388. long *high, *low;
  389. char *str;
  390. {
  391.     char *p1, *retval;
  392.     long val = 0L;
  393.     int hyphen = FALSE, more = TRUE;
  394.  
  395.     if (*str == '\0') return(NULL);
  396.     p1 = str;
  397.     while (more) {
  398.     switch (*p1) {
  399.     case '0':
  400.     case '1':
  401.     case '2':
  402.     case '3':
  403.     case '4':
  404.     case '5':
  405.     case '6':
  406.     case '7':
  407.     case '8':
  408.     case '9':
  409.             val = val * 10 + (*p1 - '0');
  410.             break;
  411.  
  412.     case '-':
  413.             *low = val;
  414.             val = 0L;
  415.             hyphen = TRUE;
  416.             break;
  417.  
  418.     case ' ':
  419.     case ',':
  420.     case '\n':
  421.             more = FALSE;
  422.             retval = ++p1;
  423.             *high = val;
  424.             if (!hyphen) *low = val;
  425.             break;
  426.  
  427.     case '\0':
  428.             more = FALSE;
  429.             retval = NULL;
  430.             *high = val;
  431.             if (!hyphen) *low = val;
  432.             return (retval);
  433.     }
  434.     p1++;
  435.     }
  436.     return (retval);
  437. }
  438.