Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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