news.c 4.1 KB

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