Subversion Repositories planix.SVN

Rev

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

/*
 *      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[] = "/lib/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(void *a, 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;

        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(void *a, 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++;
}