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[] = "/lib/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(void *a, 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 Binit(&bout, 1, OWRITE); 50 if(argc == 1) { 51 eachitem(print_item, 0, 1); 52 exits(0); 53 } 54 ARGBEGIN{ 55 case 'a': /* print all */ 56 eachitem(print_item, 1, 0); 57 break; 58 59 case 'n': /* names only */ 60 eachitem(note, 0, 0); 61 if(n_items) 62 Bputc(&bout, '\n'); 63 break; 64 65 default: 66 fprint(2, "news: bad option %c\n", ARGC()); 67 exits("usage"); 68 }ARGEND 69 for(i=0; i<argc; i++) 70 print_item(argv[i]); 71 exits(0); 72 } 73 74 int 75 fcmp(void *a, void *b) 76 { 77 long x; 78 79 x = ((File*)b)->time - ((File*)a)->time; 80 if(x < 0) 81 return -1; 82 if(x > 0) 83 return 1; 84 return 0; 85 } 86 87 /* 88 * read_dir: get the file names and modification dates for the 89 * files in /usr/news into n_list; sort them in reverse by 90 * modification date. 91 */ 92 void 93 read_dir(int update) 94 { 95 Dir *d; 96 char newstime[100], *home; 97 int i, j, n, na, fd; 98 99 n_count = 0; 100 n_list = malloc(NINC*sizeof(File)); 101 na = NINC; 102 home = getenv("home"); 103 if(home) { 104 sprint(newstime, TFILE, home); 105 d = dirstat(newstime); 106 if(d != nil) { 107 n_list[n_count].name = strdup(""); 108 n_list[n_count].time =d->mtime-1; 109 n_list[n_count].length = 0; 110 n_count++; 111 free(d); 112 } 113 if(update) { 114 fd = create(newstime, OWRITE, 0644); 115 if(fd >= 0) 116 close(fd); 117 } 118 } 119 fd = open(NEWS, OREAD); 120 if(fd < 0) { 121 fprint(2, "news: "); 122 perror(NEWS); 123 exits(NEWS); 124 } 125 126 n = dirreadall(fd, &d); 127 for(i=0; i<n; i++) { 128 for(j=0; ignore[j]; j++) 129 if(strcmp(ignore[j], d[i].name) == 0) 130 goto ign; 131 if(na <= n_count) { 132 na += NINC; 133 n_list = realloc(n_list, na*sizeof(File)); 134 } 135 n_list[n_count].name = strdup(d[i].name); 136 n_list[n_count].time = d[i].mtime; 137 n_list[n_count].length = d[i].length; 138 n_count++; 139 ign:; 140 } 141 free(d); 142 143 close(fd); 144 qsort(n_list, n_count, sizeof(File), fcmp); 145 } 146 147 void 148 print_item(char *file) 149 { 150 char name[4096], *p, *ep; 151 Dir *dbuf; 152 int f, c; 153 int bol, bop; 154 155 sprint(name, "%s/%s", NEWS, file); 156 f = open(name, OREAD); 157 if(f < 0) { 158 fprint(2, "news: "); 159 perror(name); 160 return; 161 } 162 strcpy(name, "..."); 163 dbuf = dirfstat(f); 164 if(dbuf == nil) 165 return; 166 Bprint(&bout, "\n%s (%s) %s\n", file, 167 dbuf->muid[0]? dbuf->muid : dbuf->uid, 168 asctime(localtime(dbuf->mtime))); 169 free(dbuf); 170 171 bol = 1; /* beginning of line ...\n */ 172 bop = 1; /* beginning of page ...\n\n */ 173 for(;;) { 174 c = read(f, name, sizeof(name)); 175 if(c <= 0) 176 break; 177 p = name; 178 ep = p+c; 179 while(p < ep) { 180 c = *p++; 181 if(c == '\n') { 182 if(!bop) { 183 Bputc(&bout, c); 184 if(bol) 185 bop = 1; 186 bol = 1; 187 } 188 continue; 189 } 190 if(bol) { 191 Bputc(&bout, '\t'); 192 bol = 0; 193 bop = 0; 194 } 195 Bputc(&bout, c); 196 } 197 } 198 if(!bol) 199 Bputc(&bout, '\n'); 200 close(f); 201 } 202 203 void 204 eachitem(void (*emit)(char*), int all, int update) 205 { 206 int i; 207 208 read_dir(update); 209 for(i=0; i<n_count; i++) { 210 if(n_list[i].name[0] == 0) { /* newstime */ 211 if(all) 212 continue; 213 break; 214 } 215 if(n_list[i].length == 0) /* in progress */ 216 continue; 217 (*emit)(n_list[i].name); 218 } 219 } 220 221 void 222 note(char *file) 223 { 224 225 if(!n_items) 226 Bprint(&bout, "news:"); 227 Bprint(&bout, " %s", file); 228 n_items++; 229 } 230