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