ref: 9ced712a2ad70557a8ceb89ff3b969b92c85f68c
dir: /sys/src/cmd/news.c/
/* * news foo prints /lib/news/foo * news -a prints all news items, latest first * news -n lists names of new items * news prints items changed since last news */ #include <u.h> #include <libc.h> #include <bio.h> #define NINC 50 /* Multiples of directory allocation */ char NEWS[] = "/lib/news"; char TFILE[] = "%s/lib/newstime"; /* * The following items should not be printed. */ char* ignore[] = { "core", "dead.letter", 0 }; typedef struct { long time; char *name; vlong length; } File; File* n_list; int n_count; int n_items; Biobuf bout; int fcmp(void *a, void *b); void read_dir(int update); void print_item(char *f); void eachitem(void (*emit)(char*), int all, int update); void note(char *s); void main(int argc, char *argv[]) { int i; int doupdate = 1; int printall = 0; void (*printer)(char*) = print_item; Binit(&bout, 1, OWRITE); if(argc == 1) { eachitem(print_item, printall, doupdate); exits(0); } ARGBEGIN{ case 'a': /* print all */ doupdate = 0; printall = 1; break; case 'n': /* names only */ doupdate = 0; printer = note; break; default: fprint(2, "news: bad option %c\n", ARGC()); exits("usage"); }ARGEND if (argc == 0) eachitem(printer, printall, doupdate); else for(i=0; i<argc; i++) print_item(argv[i]); if (n_items) Bputc(&bout, '\n'); exits(0); } int fcmp(void *a, void *b) { long x; x = ((File*)b)->time - ((File*)a)->time; if(x < 0) return -1; if(x > 0) return 1; return 0; } /* * read_dir: get the file names and modification dates for the * files in /usr/news into n_list; sort them in reverse by * modification date. */ void read_dir(int update) { Dir *d; char newstime[100], *home; int i, j, n, na, fd; n_count = 0; n_list = malloc(NINC*sizeof(File)); na = NINC; home = getenv("home"); if(home) { sprint(newstime, TFILE, home); d = dirstat(newstime); if(d != nil) { n_list[n_count].name = strdup(""); n_list[n_count].time =d->mtime-1; n_list[n_count].length = 0; n_count++; free(d); } if(update) { fd = create(newstime, OWRITE, 0644); if(fd >= 0) close(fd); } } fd = open(NEWS, OREAD); if(fd < 0) { fprint(2, "news: "); perror(NEWS); exits(NEWS); } n = dirreadall(fd, &d); for(i=0; i<n; i++) { for(j=0; ignore[j]; j++) if(strcmp(ignore[j], d[i].name) == 0) goto ign; if(na <= n_count) { na += NINC; n_list = realloc(n_list, na*sizeof(File)); } n_list[n_count].name = strdup(d[i].name); n_list[n_count].time = d[i].mtime; n_list[n_count].length = d[i].length; n_count++; ign:; } free(d); close(fd); qsort(n_list, n_count, sizeof(File), fcmp); } void print_item(char *file) { char name[4096], *p, *ep; Dir *dbuf; int f, c; int bol, bop; sprint(name, "%s/%s", NEWS, file); f = open(name, OREAD); if(f < 0) { fprint(2, "news: "); perror(name); return; } strcpy(name, "..."); dbuf = dirfstat(f); if(dbuf == nil) return; Bprint(&bout, "\n%s (%s) %s\n", file, dbuf->muid[0]? dbuf->muid : dbuf->uid, asctime(localtime(dbuf->mtime))); free(dbuf); bol = 1; /* beginning of line ...\n */ bop = 1; /* beginning of page ...\n\n */ for(;;) { c = read(f, name, sizeof(name)); if(c <= 0) break; p = name; ep = p+c; while(p < ep) { c = *p++; if(c == '\n') { if(!bop) { Bputc(&bout, c); if(bol) bop = 1; bol = 1; } continue; } if(bol) { Bputc(&bout, '\t'); bol = 0; bop = 0; } Bputc(&bout, c); } } if(!bol) Bputc(&bout, '\n'); close(f); } void eachitem(void (*emit)(char*), int all, int update) { int i; read_dir(update); for(i=0; i<n_count; i++) { if(n_list[i].name[0] == 0) { /* newstime */ if(all) continue; break; } if(n_list[i].length == 0) /* in progress */ continue; (*emit)(n_list[i].name); } } void note(char *file) { if(!n_items) Bprint(&bout, "news:"); Bprint(&bout, " %s", file); n_items++; }