news.c 3.7 KB

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