Blob


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 */
8 #include <u.h>
9 #include <libc.h>
10 #include <bio.h>
12 #define NINC 50 /* Multiples of directory allocation */
13 char *NEWS = "#9/news";
14 char TFILE[] = "%s/lib/newstime";
16 /*
17 * The following items should not be printed.
18 */
19 char* ignore[] =
20 {
21 "core",
22 "dead.letter",
23 0
24 };
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;
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);
44 void
45 main(int argc, char *argv[])
46 {
47 int i;
49 NEWS = unsharp(NEWS);
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;
61 case 'n': /* names only */
62 eachitem(note, 0, 0);
63 if(n_items)
64 Bputc(&bout, '\n');
65 break;
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 }
76 int
77 fcmp(const void *a, const void *b)
78 {
79 long x;
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 }
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;
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);
115 if(update) {
116 fd = create(newstime, OWRITE, 0644);
117 if(fd >= 0)
118 close(fd);
121 fd = open(NEWS, OREAD);
122 if(fd < 0) {
123 fprint(2, "news: ");
124 perror(NEWS);
125 exits(NEWS);
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));
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:;
143 free(d);
145 close(fd);
146 qsort(n_list, n_count, sizeof(File), fcmp);
149 void
150 print_item(char *file)
152 char name[4096], *p, *ep;
153 Dir *dbuf;
154 int f, c;
155 int bol, bop;
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;
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);
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;
190 continue;
192 if(bol) {
193 Bputc(&bout, '\t');
194 bol = 0;
195 bop = 0;
197 Bputc(&bout, c);
200 if(!bol)
201 Bputc(&bout, '\n');
202 close(f);
205 void
206 eachitem(void (*emit)(char*), int all, int update)
208 int i;
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;
217 if(n_list[i].length == 0) /* in progress */
218 continue;
219 (*emit)(n_list[i].name);
223 void
224 note(char *file)
227 if(!n_items)
228 Bprint(&bout, "news:");
229 Bprint(&bout, " %s", file);
230 n_items++;