|
|
1.1 root 1: /*
2: * news foo prints /usr/news/foo
3: * news -a prints all news items, latest first
4: * news -n lists names of new items
5: * news -s tells count of new items only
6: * news prints items changed since last news
7: */
8:
9: #include <stdio.h>
10: #include <sys/types.h>
11: #include <sys/stat.h>
12: #include <setjmp.h>
13: #include <signal.h>
14: #include <sys/dir.h>
15: #include <pwd.h>
16:
17: /* The number of leading spaces on each line of output */
18: #define INDENT 3
19:
20: /* The maximum number of spaces to keep together, without trying to tab */
21: #define MAXSP 2
22:
23: /*
24: * The following items should not be printed.
25: */
26: char *ignore[] = {
27: "core",
28: "dead.letter",
29: NULL
30: };
31:
32: struct n_file {
33: long n_time;
34: char n_name[DIRSIZ];
35: } *n_list;
36:
37: char NEWS[] = "/usr/news";
38:
39: int n_count;
40: char stdbuf[BUFSIZ];
41:
42: jmp_buf save_addr;
43:
44: main (argc, argv)
45: int argc;
46: char **argv;
47: {
48: int print_item(), notify(), count();
49:
50: setbuf (stdout, stdbuf);
51: initialize();
52: read_dir();
53: if (argc <= 1)
54: late_news (print_item, 1);
55: else if ( argc == 2 && argv[1][0] == '-'
56: && argv[1][1] != '\0' && argv[1][2] == '\0')
57: switch (argv[1][1]) {
58: case 'a':
59: all_news();
60: break;
61:
62: case 'n':
63: late_news (notify, 0);
64: break;
65:
66: case 's':
67: late_news (count, 0);
68: break;
69:
70: default:
71: fprintf (stderr, "news: bad option %s\n", argv[1]);
72: exit (1);
73: }
74: else {
75: int i;
76: for (i=1; i<argc; i++)
77: print_item (argv[i]);
78: }
79: return 0;
80: }
81:
82: /*
83: * read_dir: get the file names and modification dates for the
84: * files in /usr/news into n_list; sort them in reverse by
85: * modification date. We assume /usr/news is the working directory.
86: */
87:
88: read_dir()
89: {
90: struct direct nf;
91: struct stat sbuf;
92: char fname[50];
93: FILE *fd;
94: int i, j;
95: char *malloc(), *realloc();
96:
97: /* Open the current directory */
98: if ((fd = fopen (".", "r")) == NULL) {
99: fprintf (stderr, "news: ");
100: perror (NEWS);
101: exit (1);
102: }
103:
104: /* Read the file names into n_list */
105: n_count = 0;
106: while (fread ((char *) &nf, sizeof nf, 1, fd) == 1) {
107: strncpy (fname, nf.d_name, DIRSIZ);
108: if (nf.d_ino != 0 && stat (fname, &sbuf) >= 0
109: && (sbuf.st_mode & S_IFMT) == S_IFREG) {
110: register char **p;
111: p = ignore;
112: while (*p && strncmp (*p, nf.d_name, DIRSIZ))
113: ++p;
114: if (!*p) {
115: if (n_count++ > 0)
116: n_list = (struct n_file *)
117: realloc ((char *) n_list,
118: (unsigned)
119: (sizeof (struct n_file)
120: * n_count));
121: else
122: n_list = (struct n_file *) malloc
123: ((unsigned)
124: (sizeof (struct n_file) *
125: n_count));
126: if (n_list == NULL) {
127: fprintf (stderr, "news: no storage\n");
128: exit (1);
129: }
130: n_list[n_count-1].n_time = sbuf.st_mtime;
131: strncpy (n_list[n_count-1].n_name,
132: nf.d_name, DIRSIZ);
133: }
134: }
135: }
136:
137: /* Sort the elements of n_list in decreasing time order */
138: for (i=1; i<n_count; i++)
139: for (j=0; j<i; j++)
140: if (n_list[j].n_time < n_list[i].n_time) {
141: struct n_file temp;
142: temp = n_list[i];
143: n_list[i] = n_list[j];
144: n_list[j] = temp;
145: }
146:
147: /* Clean up */
148: fclose (fd);
149: }
150:
151: initialize()
152: {
153: extern _exit();
154: if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
155: signal (SIGQUIT, _exit);
156: umask (022);
157: if (chdir (NEWS) < 0) {
158: fprintf (stderr, "news: ");
159: perror (NEWS);
160: exit (1);
161: }
162: }
163:
164: all_news()
165: {
166: int i;
167:
168: for (i=0; i<n_count; i++)
169: print_item (n_list[i].n_name);
170: }
171:
172: print_item (f)
173: char *f;
174: {
175: FILE *fd;
176: char fname[DIRSIZ+1];
177: static int firstitem = 1;
178: int onintr();
179: struct passwd *getpwuid();
180:
181: if (f == NULL) {
182: return;
183: }
184: strncpy (fname, f, DIRSIZ);
185: fname[DIRSIZ] = '\0';
186: if ((fd = fopen (fname, "r")) == NULL) {
187: fprintf (stderr, "news: %s/", NEWS);
188: perror (fname);
189: } else {
190: register int c, ip, op;
191: struct stat sbuf;
192: char *ctime();
193: struct passwd *pw;
194:
195: fstat (fileno (fd), &sbuf);
196: if (firstitem) {
197: firstitem = 0;
198: putchar ('\n');
199: }
200: if (setjmp(save_addr))
201: goto finish;
202: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
203: signal(SIGINT, onintr);
204: printf ("%s ", fname);
205: pw = getpwuid (sbuf.st_uid);
206: if (pw)
207: printf ("(%s)", pw->pw_name);
208: else
209: printf (".....");
210: printf (" %s\n", ctime (&sbuf.st_mtime));
211:
212: /*
213: * copy the news item to the standard output
214: *
215: * ip is the output character position corresponding
216: * to the present input character. op is the
217: * actual current output character position.
218: */
219: op = 0;
220: ip = INDENT;
221: while ((c = getc (fd)) != EOF) {
222: switch (c) {
223:
224: case '\r':
225: case '\n':
226: putchar (c);
227: op = 0;
228: ip = INDENT;
229: break;
230:
231: case ' ':
232: ip++;
233: break;
234:
235: case '\b':
236: if (ip > INDENT)
237: ip--;
238: break;
239:
240: case '\t':
241: ip = ((ip - INDENT + 8) & -8) + INDENT;
242: break;
243:
244: default:
245: /*
246: * emit characters to get the output
247: * to the position that corresponds
248: * to this input character.
249: *
250: * first, backspace if necessary
251: */
252: while (ip < op) {
253: putchar ('\b');
254: op--;
255: }
256:
257: /*
258: * send tabs to get close to the right
259: * place. arrange to leave suitably
260: * small number of spaces as such.
261: */
262: if (ip - op > MAXSP) {
263: while ((op & -8) < (ip & -8)) {
264: putchar ('\t');
265: op = (op + 8) & -8;
266: }
267: }
268:
269: /* send spaces for fine-tuning */
270: while (ip > op) {
271: putchar (' ');
272: op++;
273: }
274:
275: /* now ip == op */
276: putchar (c);
277: ip++;
278: op++;
279: break;
280: }
281: }
282: fflush (stdout);
283: finish:
284: putchar ('\n');
285: fclose (fd);
286: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
287: signal(SIGINT, SIG_DFL);
288: }
289: }
290:
291: late_news (emit, update)
292: int (*emit)(), update;
293: {
294: long cutoff;
295: int i;
296: char fname[50], *getenv(), *cp;
297: struct stat newstime;
298: int fd;
299: struct {
300: long actime, modtime;
301: } utb;
302:
303: /* Determine the time when last called */
304: cp = getenv ("HOME");
305: if (cp == NULL) {
306: fprintf (stderr, "news: cannot find HOME variable\n");
307: exit (1);
308: }
309: strcpy (fname, cp);
310: strcat (fname, "/");
311: strcat (fname, ".news_time");
312: cutoff = stat (fname, &newstime) < 0? 0: newstime.st_mtime;
313:
314: /* Print the recent items */
315: for (i=0; i<n_count && n_list[i].n_time > cutoff; i++)
316: (*emit) (n_list[i].n_name);
317: (*emit) ((char *) NULL);
318: fflush (stdout);
319:
320: if (update) {
321: /* Re-create the file and refresh the update time */
322: if (n_count > 0 && (fd = creat (fname, 0666)) >= 0) {
323: utb.actime = utb.modtime = n_list[0].n_time;
324: close (fd);
325: utime (fname, &utb);
326: }
327: }
328: }
329:
330: notify (s)
331: char *s;
332: {
333: static int first = 1;
334:
335: if (s) {
336: if (first) {
337: first = 0;
338: printf ("news:", NEWS);
339: }
340: printf (" %.14s", s);
341: } else if (!first)
342: putchar ('\n');
343: }
344:
345: /*ARGSUSED*/
346: count (s)
347: char *s;
348: {
349: static int nitems = 0;
350:
351: if (s)
352: nitems++;
353: else if (nitems) {
354: printf ("%d news item", nitems);
355: if (nitems > 1)
356: putchar ('s');
357: printf (".\n");
358: }
359:
360: }
361:
362: onintr()
363: {
364: sleep(2);
365: longjmp(save_addr, 1);
366: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.