|
|
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.