/* $Id$ */ /* 統計今日、週、月、年熱門話題 */ #include "bbs.h" #include "fnv_hash.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 */ time4_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 */ time4_t date; /* last post's date */ int number; /* post number */ } top[TOPCOUNT], *tp; /* ---------------------------------- */ /* hash structure : array + link list */ /* ---------------------------------- */ void search(t) struct posttop *t; { struct postrec *p, *q, *s; int i, found = 0; i = fnv1a_32_str(t->title, FNV1_32_INIT) % HASHSIZE; 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; /* XXX: bid of cache.c's getbnum starts from 1 */ bid = getbnum(board); if (get_record(".BRD", &bh, sizeof(bh), bid) == -1) return 1; if (bh.brdattr & BRD_NOCOUNT) return 1; /* 板主設定不列入記錄 */ if (bh.brdattr & BRD_HIDE && !(bh.brdattr & BRD_BMCOUNT)) 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-----===== 本%s大熱門話題 =====-----\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, ctime4(&(tp->date))); buf[20] = 0; fprintf(fp, "%3d. 看板 : %-16s《 %s》%4d 篇%16s\n" " 標題 : %-60.60s\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[]; { time4_t now; struct tm *ptime; attach_SHM(); 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); } now = (time4_t)time(NULL); ptime = localtime4(&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; }