xref: /plan9/sys/src/cmd/news.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  *	news foo	prints /lib/news/foo
33e12c5d1SDavid du Colombier  *	news -a		prints all news items, latest first
43e12c5d1SDavid du Colombier  *	news -n		lists names of new items
53e12c5d1SDavid du Colombier  *	news		prints items changed since last news
63e12c5d1SDavid du Colombier  */
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier #include <u.h>
93e12c5d1SDavid du Colombier #include <libc.h>
103e12c5d1SDavid du Colombier #include <bio.h>
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier #define	NINC	50	/* Multiples of directory allocation */
133e12c5d1SDavid du Colombier char	NEWS[] = "/lib/news";
143e12c5d1SDavid du Colombier char	TFILE[] = "%s/lib/newstime";
153e12c5d1SDavid du Colombier 
163e12c5d1SDavid du Colombier /*
173e12c5d1SDavid du Colombier  *	The following items should not be printed.
183e12c5d1SDavid du Colombier  */
193e12c5d1SDavid du Colombier char*	ignore[] =
203e12c5d1SDavid du Colombier {
213e12c5d1SDavid du Colombier 	"core",
223e12c5d1SDavid du Colombier 	"dead.letter",
233e12c5d1SDavid du Colombier 	0
243e12c5d1SDavid du Colombier };
253e12c5d1SDavid du Colombier 
263e12c5d1SDavid du Colombier typedef
273e12c5d1SDavid du Colombier struct
283e12c5d1SDavid du Colombier {
293e12c5d1SDavid du Colombier 	long	time;
30*9a747e4fSDavid du Colombier 	char	*name;
31*9a747e4fSDavid du Colombier 	vlong	length;
323e12c5d1SDavid du Colombier } File;
333e12c5d1SDavid du Colombier File*	n_list;
343e12c5d1SDavid du Colombier int	n_count;
353e12c5d1SDavid du Colombier int	n_items;
363e12c5d1SDavid du Colombier Biobuf	bout;
373e12c5d1SDavid du Colombier 
383e12c5d1SDavid du Colombier int	fcmp(void *a, void *b);
393e12c5d1SDavid du Colombier void	read_dir(int update);
403e12c5d1SDavid du Colombier void	print_item(char *f);
413e12c5d1SDavid du Colombier void	eachitem(void (*emit)(char*), int all, int update);
423e12c5d1SDavid du Colombier void	note(char *s);
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier void
main(int argc,char * argv[])453e12c5d1SDavid du Colombier main(int argc, char *argv[])
463e12c5d1SDavid du Colombier {
473e12c5d1SDavid du Colombier 	int i;
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier 	Binit(&bout, 1, OWRITE);
503e12c5d1SDavid du Colombier 	if(argc == 1) {
513e12c5d1SDavid du Colombier 		eachitem(print_item, 0, 1);
523e12c5d1SDavid du Colombier 		exits(0);
533e12c5d1SDavid du Colombier 	}
543e12c5d1SDavid du Colombier 	ARGBEGIN{
553e12c5d1SDavid du Colombier 	case 'a':	/* print all */
563e12c5d1SDavid du Colombier 		eachitem(print_item, 1, 0);
573e12c5d1SDavid du Colombier 		break;
583e12c5d1SDavid du Colombier 
593e12c5d1SDavid du Colombier 	case 'n':	/* names only */
603e12c5d1SDavid du Colombier 		eachitem(note, 0, 0);
613e12c5d1SDavid du Colombier 		if(n_items)
623e12c5d1SDavid du Colombier 			Bputc(&bout, '\n');
633e12c5d1SDavid du Colombier 		break;
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier 	default:
663e12c5d1SDavid du Colombier 		fprint(2, "news: bad option %c\n", ARGC());
673e12c5d1SDavid du Colombier 		exits("usage");
683e12c5d1SDavid du Colombier 	}ARGEND
693e12c5d1SDavid du Colombier 	for(i=0; i<argc; i++)
703e12c5d1SDavid du Colombier 		print_item(argv[i]);
713e12c5d1SDavid du Colombier 	exits(0);
723e12c5d1SDavid du Colombier }
733e12c5d1SDavid du Colombier 
743e12c5d1SDavid du Colombier int
fcmp(void * a,void * b)753e12c5d1SDavid du Colombier fcmp(void *a, void *b)
763e12c5d1SDavid du Colombier {
773e12c5d1SDavid du Colombier 	long x;
783e12c5d1SDavid du Colombier 
793e12c5d1SDavid du Colombier 	x = ((File*)b)->time - ((File*)a)->time;
803e12c5d1SDavid du Colombier 	if(x < 0)
813e12c5d1SDavid du Colombier 		return -1;
823e12c5d1SDavid du Colombier 	if(x > 0)
833e12c5d1SDavid du Colombier 		return 1;
843e12c5d1SDavid du Colombier 	return 0;
853e12c5d1SDavid du Colombier }
863e12c5d1SDavid du Colombier 
873e12c5d1SDavid du Colombier /*
883e12c5d1SDavid du Colombier  *	read_dir: get the file names and modification dates for the
893e12c5d1SDavid du Colombier  *	files in /usr/news into n_list; sort them in reverse by
903e12c5d1SDavid du Colombier  *	modification date.
913e12c5d1SDavid du Colombier  */
923e12c5d1SDavid du Colombier void
read_dir(int update)933e12c5d1SDavid du Colombier read_dir(int update)
943e12c5d1SDavid du Colombier {
95*9a747e4fSDavid du Colombier 	Dir *d;
963e12c5d1SDavid du Colombier 	char newstime[100], *home;
973e12c5d1SDavid du Colombier 	int i, j, n, na, fd;
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier 	n_count = 0;
1003e12c5d1SDavid du Colombier 	n_list = malloc(NINC*sizeof(File));
1013e12c5d1SDavid du Colombier 	na = NINC;
1023e12c5d1SDavid du Colombier 	home = getenv("home");
1033e12c5d1SDavid du Colombier 	if(home) {
1043e12c5d1SDavid du Colombier 		sprint(newstime, TFILE, home);
105*9a747e4fSDavid du Colombier 		d = dirstat(newstime);
106*9a747e4fSDavid du Colombier 		if(d != nil) {
107*9a747e4fSDavid du Colombier 			n_list[n_count].name = strdup("");
108*9a747e4fSDavid du Colombier 			n_list[n_count].time =d->mtime-1;
109*9a747e4fSDavid du Colombier 			n_list[n_count].length = 0;
1103e12c5d1SDavid du Colombier 			n_count++;
111*9a747e4fSDavid du Colombier 			free(d);
1123e12c5d1SDavid du Colombier 		}
1133e12c5d1SDavid du Colombier 		if(update) {
1147dd7cddfSDavid du Colombier 			fd = create(newstime, OWRITE, 0644);
1153e12c5d1SDavid du Colombier 			if(fd >= 0)
1163e12c5d1SDavid du Colombier 				close(fd);
1173e12c5d1SDavid du Colombier 		}
1183e12c5d1SDavid du Colombier 	}
1193e12c5d1SDavid du Colombier 	fd = open(NEWS, OREAD);
1203e12c5d1SDavid du Colombier 	if(fd < 0) {
1213e12c5d1SDavid du Colombier 		fprint(2, "news: ");
1223e12c5d1SDavid du Colombier 		perror(NEWS);
1233e12c5d1SDavid du Colombier 		exits(NEWS);
1243e12c5d1SDavid du Colombier 	}
125*9a747e4fSDavid du Colombier 
126*9a747e4fSDavid du Colombier 	n = dirreadall(fd, &d);
1273e12c5d1SDavid du Colombier 	for(i=0; i<n; i++) {
1283e12c5d1SDavid du Colombier 		for(j=0; ignore[j]; j++)
129*9a747e4fSDavid du Colombier 			if(strcmp(ignore[j], d[i].name) == 0)
1303e12c5d1SDavid du Colombier 				goto ign;
1313e12c5d1SDavid du Colombier 		if(na <= n_count) {
1323e12c5d1SDavid du Colombier 			na += NINC;
1333e12c5d1SDavid du Colombier 			n_list = realloc(n_list, na*sizeof(File));
1343e12c5d1SDavid du Colombier 		}
135*9a747e4fSDavid du Colombier 		n_list[n_count].name = strdup(d[i].name);
136*9a747e4fSDavid du Colombier 		n_list[n_count].time = d[i].mtime;
137*9a747e4fSDavid du Colombier 		n_list[n_count].length = d[i].length;
1383e12c5d1SDavid du Colombier 		n_count++;
1393e12c5d1SDavid du Colombier 	ign:;
1403e12c5d1SDavid du Colombier 	}
141*9a747e4fSDavid du Colombier 	free(d);
142*9a747e4fSDavid du Colombier 
1433e12c5d1SDavid du Colombier 	close(fd);
1443e12c5d1SDavid du Colombier 	qsort(n_list, n_count, sizeof(File), fcmp);
1453e12c5d1SDavid du Colombier }
1463e12c5d1SDavid du Colombier 
1473e12c5d1SDavid du Colombier void
print_item(char * file)1483e12c5d1SDavid du Colombier print_item(char *file)
1493e12c5d1SDavid du Colombier {
1503e12c5d1SDavid du Colombier 	char name[4096], *p, *ep;
151*9a747e4fSDavid du Colombier 	Dir *dbuf;
1527dd7cddfSDavid du Colombier 	int f, c;
1533e12c5d1SDavid du Colombier 	int bol, bop;
1543e12c5d1SDavid du Colombier 
1553e12c5d1SDavid du Colombier 	sprint(name, "%s/%s", NEWS, file);
1563e12c5d1SDavid du Colombier 	f = open(name, OREAD);
1573e12c5d1SDavid du Colombier 	if(f < 0) {
1583e12c5d1SDavid du Colombier 		fprint(2, "news: ");
1593e12c5d1SDavid du Colombier 		perror(name);
1603e12c5d1SDavid du Colombier 		return;
1613e12c5d1SDavid du Colombier 	}
1623e12c5d1SDavid du Colombier 	strcpy(name, "...");
163*9a747e4fSDavid du Colombier 	dbuf = dirfstat(f);
164*9a747e4fSDavid du Colombier 	if(dbuf == nil)
1653e12c5d1SDavid du Colombier 		return;
1663e12c5d1SDavid du Colombier 	Bprint(&bout, "\n%s (%s) %s\n", file,
167*9a747e4fSDavid du Colombier 		dbuf->muid[0]? dbuf->muid : dbuf->uid,
168*9a747e4fSDavid du Colombier 		asctime(localtime(dbuf->mtime)));
169*9a747e4fSDavid du Colombier 	free(dbuf);
1703e12c5d1SDavid du Colombier 
1713e12c5d1SDavid du Colombier 	bol = 1;	/* beginning of line ...\n */
1723e12c5d1SDavid du Colombier 	bop = 1;	/* beginning of page ...\n\n */
1733e12c5d1SDavid du Colombier 	for(;;) {
1743e12c5d1SDavid du Colombier 		c = read(f, name, sizeof(name));
1753e12c5d1SDavid du Colombier 		if(c <= 0)
1763e12c5d1SDavid du Colombier 			break;
1773e12c5d1SDavid du Colombier 		p = name;
1783e12c5d1SDavid du Colombier 		ep = p+c;
1793e12c5d1SDavid du Colombier 		while(p < ep) {
1803e12c5d1SDavid du Colombier 			c = *p++;
1813e12c5d1SDavid du Colombier 			if(c == '\n') {
1823e12c5d1SDavid du Colombier 				if(!bop) {
1833e12c5d1SDavid du Colombier 					Bputc(&bout, c);
1843e12c5d1SDavid du Colombier 					if(bol)
1853e12c5d1SDavid du Colombier 						bop = 1;
1863e12c5d1SDavid du Colombier 					bol = 1;
1873e12c5d1SDavid du Colombier 				}
1883e12c5d1SDavid du Colombier 				continue;
1893e12c5d1SDavid du Colombier 			}
1903e12c5d1SDavid du Colombier 			if(bol) {
1917dd7cddfSDavid du Colombier 				Bputc(&bout, '\t');
1923e12c5d1SDavid du Colombier 				bol = 0;
1933e12c5d1SDavid du Colombier 				bop = 0;
1943e12c5d1SDavid du Colombier 			}
1953e12c5d1SDavid du Colombier 			Bputc(&bout, c);
1963e12c5d1SDavid du Colombier 		}
1973e12c5d1SDavid du Colombier 	}
1983e12c5d1SDavid du Colombier 	if(!bol)
1993e12c5d1SDavid du Colombier 		Bputc(&bout, '\n');
2003e12c5d1SDavid du Colombier 	close(f);
2013e12c5d1SDavid du Colombier }
2023e12c5d1SDavid du Colombier 
2033e12c5d1SDavid du Colombier void
eachitem(void (* emit)(char *),int all,int update)2043e12c5d1SDavid du Colombier eachitem(void (*emit)(char*), int all, int update)
2053e12c5d1SDavid du Colombier {
2063e12c5d1SDavid du Colombier 	int i;
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier 	read_dir(update);
2093e12c5d1SDavid du Colombier 	for(i=0; i<n_count; i++) {
2103e12c5d1SDavid du Colombier 		if(n_list[i].name[0] == 0) {	/* newstime */
2113e12c5d1SDavid du Colombier 			if(all)
2123e12c5d1SDavid du Colombier 				continue;
2133e12c5d1SDavid du Colombier 			break;
2143e12c5d1SDavid du Colombier 		}
215*9a747e4fSDavid du Colombier 		if(n_list[i].length == 0)		/* in progress */
216*9a747e4fSDavid du Colombier 			continue;
2173e12c5d1SDavid du Colombier 		(*emit)(n_list[i].name);
2183e12c5d1SDavid du Colombier 	}
2193e12c5d1SDavid du Colombier }
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier void
note(char * file)2223e12c5d1SDavid du Colombier note(char *file)
2233e12c5d1SDavid du Colombier {
2243e12c5d1SDavid du Colombier 
2253e12c5d1SDavid du Colombier 	if(!n_items)
2263e12c5d1SDavid du Colombier 		Bprint(&bout, "news:");
2273e12c5d1SDavid du Colombier 	Bprint(&bout, " %s", file);
2283e12c5d1SDavid du Colombier 	n_items++;
2293e12c5d1SDavid du Colombier }
230