diff options
Diffstat (limited to 'util/poststat.c')
-rw-r--r-- | util/poststat.c | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/util/poststat.c b/util/poststat.c new file mode 100644 index 00000000..3aa3cc94 --- /dev/null +++ b/util/poststat.c @@ -0,0 +1,497 @@ +/* $Id: poststat.c,v 1.1 2002/03/07 15:13:46 in2 Exp $ */ +/* 統計今日、週、月、年熱門話題 */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> + +#ifdef __FreeBSD__ +#include <machine/param.h> +#endif + +#include "config.h" +#include "pttstruct.h" + +char *myfile[] = +{"day", "week", "month", "year"}; +int mycount[4] = +{7, 4, 12}; +int mytop[] = +{10, 50, 100, 100}; +char *mytitle[] = +{"日十", "週五十", "月百", "年度百"}; + + +#define HASHSIZE 1024 +#define TOPCOUNT 200 + + +struct postrec +{ + char author[13]; /* author name */ + char board[13]; /* board name */ + char title[66]; /* title name */ + time_t date; /* last post's date */ + int number; /* post number */ + struct postrec *next; /* next rec */ +} +*bucket[HASHSIZE]; + + +/* 100 bytes */ +struct posttop +{ + char author[13]; /* author name */ + char board[13]; /* board name */ + char title[66]; /* title name */ + time_t date; /* last post's date */ + int number; /* post number */ +} +top[TOPCOUNT], *tp; + + + +/* + woju + Cross-fs rename() + */ + +int Rename(char *src, char *dst) +{ + + if (rename(src, dst) == 0) + return 0; +/* + sprintf(cmd, "/bin/mv %s %s", src, dst); + return system(cmd); +*/ + return 0; +} + + + +/*-------------------------------------------------------*/ +/* .BOARDS cache */ +/*-------------------------------------------------------*/ + +struct bcache_t *brdshm; +boardheader_t *bcache; +int numboards = -1; + + +static void +attach_err(shmkey, name) + int shmkey; + char *name; +{ + fprintf(stderr, "[%s error] key = %x\n", name, shmkey); + exit(1); +} + + +static void * +attach_shm(shmkey, shmsize) + int shmkey, shmsize; +{ + void *shmptr; + int shmid; + + shmid = shmget(shmkey, shmsize, 0); + if (shmid < 0) + { + shmid = shmget(shmkey, shmsize, IPC_CREAT | 0600); + if (shmid < 0) + attach_err(shmkey, "shmget"); + shmptr = (void *) shmat(shmid, NULL, 0); + if (shmptr == (void *) -1) + attach_err(shmkey, "shmat"); + memset(shmptr, 0, shmsize); + } + else + { + shmptr = (void *) shmat(shmid, NULL, 0); + if (shmptr == (void *) -1) + attach_err(shmkey, "shmat"); + } + return shmptr; +} + + + +void +resolve_boards() +{ + if (brdshm == NULL) + { + brdshm = attach_shm(BRDSHM_KEY, sizeof(*brdshm)); + if (brdshm->touchtime == 0) + brdshm->touchtime = 1; + bcache = brdshm->bcache; + } + + while (brdshm->uptime < brdshm->touchtime) + { + if (brdshm->busystate) + { + sleep(1); + } + else + { + int fd; + + brdshm->busystate = 1; + + if ((fd = open(".BOARDS", O_RDONLY)) > 0) + { + brdshm->number = read(fd, bcache, MAX_BOARD * sizeof(boardheader_t)) + / sizeof(boardheader_t); + close(fd); + } + + /* 等所有 boards 資料更新後再設定 uptime */ + + brdshm->uptime = brdshm->touchtime; + brdshm->busystate = 0; + } + } + numboards = brdshm->number; +} + + +int +ci_strcmp(s1, s2) + register char *s1, *s2; +{ + register int c1, c2, diff; + + do + { + c1 = *s1++; + c2 = *s2++; + if (c1 >= 'A' && c1 <= 'Z') + c1 |= 32; + if (c2 >= 'A' && c2 <= 'Z') + c2 |= 32; + if((diff = c1 - c2)) + return (diff); + } + while (c1); + return 0; +} + +int +get_record(fpath, rptr, size, id) + char *fpath; + char *rptr; + int size, id; +{ + int fd; + + if ((fd = open(fpath, O_RDONLY, 0)) != -1) + { + if (lseek(fd, size * (id - 1), SEEK_SET) != -1) + { + if (read(fd, rptr, size) == size) + { + close(fd); + return 0; + } + } + close(fd); + } + return -1; +} + + +int +getbnum(bname) + char *bname; +{ + register int i; + register boardheader_t *bhdr; + + resolve_boards(); + for (i = 0, bhdr = bcache; i++ < numboards; bhdr++) + /* if (Ben_Perm(bhdr)) */ + if (!ci_strcmp(bname, bhdr->brdname)) + return i; + return 0; +} + + +int +hash(key) + char *key; +{ + int i, value = 0; + + for (i = 0; key[i] && i < 80; i++) + value += key[i] < 0 ? -key[i] : key[i]; + + value = value % HASHSIZE; + return value; +} + + +/* ---------------------------------- */ +/* hash structure : array + link list */ +/* ---------------------------------- */ + + +void +search(t) + struct posttop *t; +{ + struct postrec *p, *q, *s; + int i, found = 0; + + i = hash(t->title); + q = NULL; + p = bucket[i]; + while (p && (!found)) + { + if (!strcmp(p->title, t->title) && !strcmp(p->board, t->board)) + found = 1; + else + { + q = p; + p = p->next; + } + } + if (found) + { + p->number += t->number; + if (p->date < t->date) /* 取較近日期 */ + p->date = t->date; + } + else + { + s = (struct postrec *) malloc(sizeof(struct postrec)); + memcpy(s, t, sizeof(struct posttop)); + s->next = NULL; + if (q == NULL) + bucket[i] = s; + else + q->next = s; + } +} + + +int +sort(pp, count) + struct postrec *pp; +{ + int i, j; + + for (i = 0; i <= count; i++) + { + if (pp->number > top[i].number) + { + if (count < TOPCOUNT - 1) + count++; + for (j = count - 1; j >= i; j--) + memcpy(&top[j + 1], &top[j], sizeof(struct posttop)); + + memcpy(&top[i], pp, sizeof(struct posttop)); + break; + } + } + return count; +} + + +void +load_stat(fname) + char *fname; +{ + FILE *fp; + + if((fp = fopen(fname, "r"))) + { + int count = fread(top, sizeof(struct posttop), TOPCOUNT, fp); + fclose(fp); + while (count) + search(&top[--count]); + } +} + + +int +filter(board) + char *board; +{ + boardheader_t bh; + int bid; + + bid = getbnum(board); + if (get_record(".BOARDS", &bh, sizeof(bh), bid) == -1) + return 1; + if (bh.brdattr & BRD_NOCOUNT) + return 1; +/* + if (bh.brdattr & BRD_POSTMASK) + return 0; + return (bh.brdattr & ~BRD_POSTMASK) || + >= 32; +*/ + return 0; +} + + +void +poststat(mytype) + int mytype; +{ + static char *logfile = ".post"; + static char *oldfile = ".post.old"; + + FILE *fp; + char buf[40], curfile[40] = "etc/day.0", *p; + struct postrec *pp; + int i, j; + + if (mytype < 0) + { + /* --------------------------------------- */ + /* load .post and statictic processing */ + /* --------------------------------------- */ + + remove(oldfile); + Rename(logfile, oldfile); + if ((fp = fopen(oldfile, "r")) == NULL) + return; + mytype = 0; + load_stat(curfile); + + while (fread(top, sizeof(struct posttop), 1, fp)) + search(top); + fclose(fp); + } + else + { + /* ---------------------------------------------- */ + /* load previous results and statictic processing */ + /* ---------------------------------------------- */ + + i = mycount[mytype]; + p = myfile[mytype]; + while (i) + { + sprintf(buf, "etc/%s.%d", p, i); + sprintf(curfile, "etc/%s.%d", p, --i); + load_stat(curfile); + Rename(curfile, buf); + } + mytype++; + } + +/* ---------------------------------------------- */ +/* sort top 100 issue and save results */ +/* ---------------------------------------------- */ + + memset(top, 0, sizeof(top)); + for (i = j = 0; i < HASHSIZE; i++) + { + for (pp = bucket[i]; pp; pp = pp->next) + { +#ifdef DEBUG + printf("Title : %s, Board: %s\nPostNo : %d, Author: %s\n" + ,pp->title + ,pp->board + ,pp->number + ,pp->author); +#endif + + j = sort(pp, j); + } + } + + p = myfile[mytype]; + sprintf(curfile, "etc/%s.0", p); + if((fp = fopen(curfile, "w"))) + { + fwrite(top, sizeof(struct posttop), j, fp); + fclose(fp); + } + + sprintf(curfile, "etc/%s", p); + if((fp = fopen(curfile, "w"))) + { + int max, cnt; + + fprintf(fp, "\t\t[1;34m-----[37m=====[41m 本%s大熱門話題 [40m=====[34m-----[0m\n\n", mytitle[mytype]); + + max = mytop[mytype]; + p = buf + 4; + for (i = cnt = 0; (cnt < max) && (i < j); i++) + { + tp = &top[i]; + if (filter(tp->board)) + continue; + + strcpy(buf, ctime(&(tp->date))); + buf[20] = 0; + fprintf(fp, + "[1;31m%3d. [33m看板 : [32m%-16s[35m《 %s》[36m%4d 篇[33m%16s\n" + " [33m標題 : [0;44;37m%-60.60s[40m\n" + ,++cnt, tp->board, p, tp->number, tp->author, tp->title); + } + fclose(fp); + } + +/* free statistics */ + + for (i = 0; i < HASHSIZE; i++) + { + struct postrec *pp0; + + pp = bucket[i]; + while (pp) + { + pp0 = pp; + pp = pp->next; + free(pp0); + } + + bucket[i] = NULL; + } +} + + +int main(argc, argv) + char *argv[]; +{ + time_t now; + struct tm *ptime; + + if (argc < 2) + { + printf("Usage:\t%s bbshome [day]\n", argv[0]); + return (-1); + } + chdir(argv[1]); + + if (argc == 3) + { + poststat(atoi(argv[2])); + return (0); + } + time(&now); + ptime = localtime(&now); + if (ptime->tm_hour == 0) + { + if (ptime->tm_mday == 1) + poststat(2); + + if (ptime->tm_wday == 0) + poststat(1); + poststat(0); + } + poststat(-1); + return 0; +} |