news.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 }