blob: bdffaa39d91e308961135138c6a07d4dcf69b38b [file] [log] [blame]
/*
* 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++;
}