]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/news.c
fork filter procs with RFREND in various programs
[plan9front.git] / sys / src / cmd / news.c
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 }