aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/news.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-21 23:22:06 +0000
committerrsc <devnull@localhost>2004-04-21 23:22:06 +0000
commit17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b (patch)
tree921c649de0d83bdde4561f5868e5ff3ab9986af8 /src/cmd/news.c
parent3e63e5c271f7a7013dc4b3fedfb83c2d547b8c26 (diff)
downloadplan9port-17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b.tar.gz
plan9port-17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b.tar.bz2
plan9port-17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b.zip
add new guys
Diffstat (limited to 'src/cmd/news.c')
-rw-r--r--src/cmd/news.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/cmd/news.c b/src/cmd/news.c
new file mode 100644
index 00000000..c6a99a30
--- /dev/null
+++ b/src/cmd/news.c
@@ -0,0 +1,231 @@
+/*
+ * news foo prints /lib/news/foo
+ * news -a prints all news items, latest first
+ * news -n lists names of new items
+ * news prints items changed since last news
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#define NINC 50 /* Multiples of directory allocation */
+char *NEWS = "#9/news";
+char TFILE[] = "%s/lib/newstime";
+
+/*
+ * The following items should not be printed.
+ */
+char* ignore[] =
+{
+ "core",
+ "dead.letter",
+ 0
+};
+
+typedef
+struct
+{
+ long time;
+ char *name;
+ vlong length;
+} File;
+File* n_list;
+int n_count;
+int n_items;
+Biobuf bout;
+
+int fcmp(const void *a, const void *b);
+void read_dir(int update);
+void print_item(char *f);
+void eachitem(void (*emit)(char*), int all, int update);
+void note(char *s);
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+
+ NEWS = unsharp(NEWS);
+
+ Binit(&bout, 1, OWRITE);
+ if(argc == 1) {
+ eachitem(print_item, 0, 1);
+ exits(0);
+ }
+ ARGBEGIN{
+ case 'a': /* print all */
+ eachitem(print_item, 1, 0);
+ break;
+
+ case 'n': /* names only */
+ eachitem(note, 0, 0);
+ if(n_items)
+ Bputc(&bout, '\n');
+ break;
+
+ default:
+ fprint(2, "news: bad option %c\n", ARGC());
+ exits("usage");
+ }ARGEND
+ for(i=0; i<argc; i++)
+ print_item(argv[i]);
+ exits(0);
+}
+
+int
+fcmp(const void *a, const void *b)
+{
+ long x;
+
+ x = ((File*)b)->time - ((File*)a)->time;
+ if(x < 0)
+ return -1;
+ if(x > 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * read_dir: get the file names and modification dates for the
+ * files in /usr/news into n_list; sort them in reverse by
+ * modification date.
+ */
+void
+read_dir(int update)
+{
+ Dir *d;
+ char newstime[100], *home;
+ int i, j, n, na, fd;
+
+ n_count = 0;
+ n_list = malloc(NINC*sizeof(File));
+ na = NINC;
+ home = getenv("home");
+ if(home) {
+ sprint(newstime, TFILE, home);
+ d = dirstat(newstime);
+ if(d != nil) {
+ n_list[n_count].name = strdup("");
+ n_list[n_count].time =d->mtime-1;
+ n_list[n_count].length = 0;
+ n_count++;
+ free(d);
+ }
+ if(update) {
+ fd = create(newstime, OWRITE, 0644);
+ if(fd >= 0)
+ close(fd);
+ }
+ }
+ fd = open(NEWS, OREAD);
+ if(fd < 0) {
+ fprint(2, "news: ");
+ perror(NEWS);
+ exits(NEWS);
+ }
+
+ n = dirreadall(fd, &d);
+ for(i=0; i<n; i++) {
+ for(j=0; ignore[j]; j++)
+ if(strcmp(ignore[j], d[i].name) == 0)
+ goto ign;
+ if(na <= n_count) {
+ na += NINC;
+ n_list = realloc(n_list, na*sizeof(File));
+ }
+ n_list[n_count].name = strdup(d[i].name);
+ n_list[n_count].time = d[i].mtime;
+ n_list[n_count].length = d[i].length;
+ n_count++;
+ ign:;
+ }
+ free(d);
+
+ close(fd);
+ qsort(n_list, n_count, sizeof(File), fcmp);
+}
+
+void
+print_item(char *file)
+{
+ char name[4096], *p, *ep;
+ Dir *dbuf;
+ int f, c;
+ int bol, bop;
+
+ sprint(name, "%s/%s", NEWS, file);
+ f = open(name, OREAD);
+ if(f < 0) {
+ fprint(2, "news: ");
+ perror(name);
+ return;
+ }
+ strcpy(name, "...");
+ dbuf = dirfstat(f);
+ if(dbuf == nil)
+ return;
+ Bprint(&bout, "\n%s (%s) %s\n", file,
+ dbuf->muid[0]? dbuf->muid : dbuf->uid,
+ asctime(localtime(dbuf->mtime)));
+ free(dbuf);
+
+ bol = 1; /* beginning of line ...\n */
+ bop = 1; /* beginning of page ...\n\n */
+ for(;;) {
+ c = read(f, name, sizeof(name));
+ if(c <= 0)
+ break;
+ p = name;
+ ep = p+c;
+ while(p < ep) {
+ c = *p++;
+ if(c == '\n') {
+ if(!bop) {
+ Bputc(&bout, c);
+ if(bol)
+ bop = 1;
+ bol = 1;
+ }
+ continue;
+ }
+ if(bol) {
+ Bputc(&bout, '\t');
+ bol = 0;
+ bop = 0;
+ }
+ Bputc(&bout, c);
+ }
+ }
+ if(!bol)
+ Bputc(&bout, '\n');
+ close(f);
+}
+
+void
+eachitem(void (*emit)(char*), int all, int update)
+{
+ int i;
+
+ read_dir(update);
+ for(i=0; i<n_count; i++) {
+ if(n_list[i].name[0] == 0) { /* newstime */
+ if(all)
+ continue;
+ break;
+ }
+ if(n_list[i].length == 0) /* in progress */
+ continue;
+ (*emit)(n_list[i].name);
+ }
+}
+
+void
+note(char *file)
+{
+
+ if(!n_items)
+ Bprint(&bout, "news:");
+ Bprint(&bout, " %s", file);
+ n_items++;
+}