URI:
       tnews.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tnews.c (3823B)
       ---
            1 /*
            2  *        news foo        prints /lib/news/foo
            3  *        news -a                prints all news items, latest first
            4  *        news -n                lists names of new items
            5  *        news                prints items changed since last news
            6  */
            7 
            8 #include <u.h>
            9 #include <libc.h>
           10 #include <bio.h>
           11 
           12 #define        NINC        50        /* Multiples of directory allocation */
           13 char        *NEWS = "#9/news";
           14 char        TFILE[] = "%s/lib/newstime";
           15 
           16 /*
           17  *        The following items should not be printed.
           18  */
           19 char*        ignore[] =
           20 {
           21         "core",
           22         "dead.letter",
           23         0
           24 };
           25 
           26 typedef
           27 struct
           28 {
           29         long        time;
           30         char        *name;
           31         vlong        length;
           32 } File;
           33 File*        n_list;
           34 int        n_count;
           35 int        n_items;
           36 Biobuf        bout;
           37 
           38 int        fcmp(const void *a, const void *b);
           39 void        read_dir(int update);
           40 void        print_item(char *f);
           41 void        eachitem(void (*emit)(char*), int all, int update);
           42 void        note(char *s);
           43 
           44 void
           45 main(int argc, char *argv[])
           46 {
           47         int i;
           48 
           49         NEWS = unsharp(NEWS);
           50 
           51         Binit(&bout, 1, OWRITE);
           52         if(argc == 1) {
           53                 eachitem(print_item, 0, 1);
           54                 exits(0);
           55         }
           56         ARGBEGIN{
           57         case 'a':        /* print all */
           58                 eachitem(print_item, 1, 0);
           59                 break;
           60 
           61         case 'n':        /* names only */
           62                 eachitem(note, 0, 0);
           63                 if(n_items)
           64                         Bputc(&bout, '\n');
           65                 break;
           66 
           67         default:
           68                 fprint(2, "news: bad option %c\n", ARGC());
           69                 exits("usage");
           70         }ARGEND
           71         for(i=0; i<argc; i++)
           72                 print_item(argv[i]);
           73         exits(0);
           74 }
           75 
           76 int
           77 fcmp(const void *a, const void *b)
           78 {
           79         long x;
           80 
           81         x = ((File*)b)->time - ((File*)a)->time;
           82         if(x < 0)
           83                 return -1;
           84         if(x > 0)
           85                 return 1;
           86         return 0;
           87 }
           88 
           89 /*
           90  *        read_dir: get the file names and modification dates for the
           91  *        files in /usr/news into n_list; sort them in reverse by
           92  *        modification date.
           93  */
           94 void
           95 read_dir(int update)
           96 {
           97         Dir *d;
           98         char newstime[100], *home;
           99         int i, j, n, na, fd;
          100 
          101         n_count = 0;
          102         n_list = malloc(NINC*sizeof(File));
          103         na = NINC;
          104         home = getenv("HOME");
          105         if(home) {
          106                 sprint(newstime, TFILE, home);
          107                 d = dirstat(newstime);
          108                 if(d != nil) {
          109                         n_list[n_count].name = strdup("");
          110                         n_list[n_count].time =d->mtime-1;
          111                         n_list[n_count].length = 0;
          112                         n_count++;
          113                         free(d);
          114                 }
          115                 if(update) {
          116                         fd = create(newstime, OWRITE, 0644);
          117                         if(fd >= 0)
          118                                 close(fd);
          119                 }
          120         }
          121         fd = open(NEWS, OREAD);
          122         if(fd < 0) {
          123                 fprint(2, "news: ");
          124                 perror(NEWS);
          125                 exits(NEWS);
          126         }
          127 
          128         n = dirreadall(fd, &d);
          129         for(i=0; i<n; i++) {
          130                 for(j=0; ignore[j]; j++)
          131                         if(strcmp(ignore[j], d[i].name) == 0)
          132                                 goto ign;
          133                 if(na <= n_count) {
          134                         na += NINC;
          135                         n_list = realloc(n_list, na*sizeof(File));
          136                 }
          137                 n_list[n_count].name = strdup(d[i].name);
          138                 n_list[n_count].time = d[i].mtime;
          139                 n_list[n_count].length = d[i].length;
          140                 n_count++;
          141         ign:;
          142         }
          143         free(d);
          144 
          145         close(fd);
          146         qsort(n_list, n_count, sizeof(File), fcmp);
          147 }
          148 
          149 void
          150 print_item(char *file)
          151 {
          152         char name[4096], *p, *ep;
          153         Dir *dbuf;
          154         int f, c;
          155         int bol, bop;
          156 
          157         sprint(name, "%s/%s", NEWS, file);
          158         f = open(name, OREAD);
          159         if(f < 0) {
          160                 fprint(2, "news: ");
          161                 perror(name);
          162                 return;
          163         }
          164         strcpy(name, "...");
          165         dbuf = dirfstat(f);
          166         if(dbuf == nil)
          167                 return;
          168         Bprint(&bout, "\n%s (%s) %s\n", file,
          169                 dbuf->muid[0]? dbuf->muid : dbuf->uid,
          170                 asctime(localtime(dbuf->mtime)));
          171         free(dbuf);
          172 
          173         bol = 1;        /* beginning of line ...\n */
          174         bop = 1;        /* beginning of page ...\n\n */
          175         for(;;) {
          176                 c = read(f, name, sizeof(name));
          177                 if(c <= 0)
          178                         break;
          179                 p = name;
          180                 ep = p+c;
          181                 while(p < ep) {
          182                         c = *p++;
          183                         if(c == '\n') {
          184                                 if(!bop) {
          185                                         Bputc(&bout, c);
          186                                         if(bol)
          187                                                 bop = 1;
          188                                         bol = 1;
          189                                 }
          190                                 continue;
          191                         }
          192                         if(bol) {
          193                                 Bputc(&bout, '\t');
          194                                 bol = 0;
          195                                 bop = 0;
          196                         }
          197                         Bputc(&bout, c);
          198                 }
          199         }
          200         if(!bol)
          201                 Bputc(&bout, '\n');
          202         close(f);
          203 }
          204 
          205 void
          206 eachitem(void (*emit)(char*), int all, int update)
          207 {
          208         int i;
          209 
          210         read_dir(update);
          211         for(i=0; i<n_count; i++) {
          212                 if(n_list[i].name[0] == 0) {        /* newstime */
          213                         if(all)
          214                                 continue;
          215                         break;
          216                 }
          217                 if(n_list[i].length == 0)                /* in progress */
          218                         continue;
          219                 (*emit)(n_list[i].name);
          220         }
          221 }
          222 
          223 void
          224 note(char *file)
          225 {
          226 
          227         if(!n_items)
          228                 Bprint(&bout, "news:");
          229         Bprint(&bout, " %s", file);
          230         n_items++;
          231 }