plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

news.c (3823B)


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