/* $Id$ */
/* 'mandex -h' to help */
#include "bbs.h"
typedef struct {
char bname[40];
int ndir, nfile, k;
} boardinfo_t;
static const char *color[4] = {"[1;33m", "[1;32m", "[1;36m", "[1;37m"};
static const char *fn_index = ".index";
static const char *fn_new = ".index.new";
static const char *index_title = "◎ 精華區目錄索引";;
int sortbyname(const void *a, const void *b)
{
return strcmp(((boardinfo_t*)b)->bname, ((boardinfo_t*)a)->bname);
}
int k_cmp(const void *x, const void *y)
{
const boardinfo_t *b = (boardinfo_t *)x, *a = (boardinfo_t *)y;
return ((a->k / 100 + a->ndir + a->nfile) - (b->k / 100 + b->ndir + b->nfile));
}
static FILE *fp_index;
static boardinfo_t curr_brdinfo;
/* visit the hierarchy recursively */
void
mandex(const int level, const char *num_header, char *fpath)
{
FILE *fp_dir;
char *fname, buf[512];
int count;
fileheader_t fhdr;
if ((fp_dir = fopen(fpath, "r")) == NULL)
return;
fname = strrchr(fpath, '/') + 1;
count = 0;
while (fread(&fhdr, sizeof(fhdr), 1, fp_dir) == 1) {
++count;
if (!fhdr.filename[0])
continue;
*fname = '\0';
strlcat(fpath, fhdr.filename, PATHLEN);
snprintf(buf, sizeof(buf), "%.*s%s%3d. %s [m\n",
11 * level, num_header, color[level % 4], count, fhdr.title);
/* Ptt */
fputs(buf, fp_index);
if (dashd(fpath)) {
curr_brdinfo.ndir++;
if (level < 10 && !(fhdr.filemode & (FILE_BM|FILE_HIDE))) {
strlcat(fpath, "/" FN_DIR, PATHLEN);
mandex(level + 1, buf, fpath);
}
}
else
curr_brdinfo.nfile++;
}
fclose(fp_dir);
}
void
man_index(const char * brdname)
{
char buf[PATHLEN], fpath[PATHLEN], *p;
int i, index_pos = -1;
FILE *fp_dir;
struct stat st;
fileheader_t fhdr;
const boardheader_t *bptr;
if ((i = getbnum(brdname)) == 0)
return;
bptr = getbcache(i);
if (strcmp(brdname, bptr->brdname) != 0)
return;
memset(&curr_brdinfo, 0, sizeof(curr_brdinfo));
strlcpy(curr_brdinfo.bname, brdname, sizeof(curr_brdinfo.bname));
setapath(buf, brdname);
setadir(fpath, buf);
setdirpath(buf, fpath, fn_new);
if ((fp_index = fopen(buf, "w")) == NULL)
return;
fprintf(fp_index, "[1;32m序號\t\t\t精華區主題[m\n"
"[36m───────────────────"
"───────────────────[m\n");
printf("%s ", fpath);
mandex(0, "", fpath);
fclose(fp_index);
stat(buf, &st);
curr_brdinfo.k = st.st_size;
printf("(%s)[%dK] d: %d f: %d\n", buf, curr_brdinfo.k, curr_brdinfo.ndir, curr_brdinfo.nfile);
setdirpath(fpath, buf, fn_index);
rename(buf, fpath);
setdirpath(fpath, buf, FN_DIR);
sprintf(buf, "%s.new", fpath);
if ((fp_dir = fopen(fpath, "r+")) == NULL)
return;
if ((fp_index = fopen(buf, "w")) == NULL) {
fclose(fp_dir);
return;
}
i = 0;
while (fread(&fhdr, sizeof(fhdr), 1, fp_dir) == 1) {
if (strncmp(fhdr.title, index_title, strlen(index_title)) == 0) {
index_pos = i;
setdirpath(buf, fpath, fhdr.filename);
unlink(buf);
break;
}
i++;
}
p = strrchr(buf, '/');
*p = '\0';
stamplink(buf, &fhdr);
unlink(buf);
symlink(fn_index, buf);
strlcpy(fhdr.owner, "每天自動更新", sizeof(fhdr.owner));
snprintf(fhdr.title, sizeof(fhdr.title), "%s (%.1fk)", index_title, st.st_size / 1024.);
sprintf(buf, "%s.new", fpath);
if (index_pos >= 0) {
fseek(fp_dir, index_pos * sizeof(fhdr), SEEK_SET);
fwrite(&fhdr, sizeof(fhdr), 1, fp_dir);
unlink(buf);
} else {
fwrite(&fhdr, sizeof(fhdr), 1, fp_index);
rewind(fp_dir);
while (fread(&fhdr, sizeof(fhdr), 1, fp_dir) == 1)
fwrite(&fhdr, sizeof(fhdr), 1, fp_index);
rename(buf, fpath);
}
fclose(fp_index);
fclose(fp_dir);
}
void
output_chart(const boardinfo_t * board, const int nbrds)
{
FILE * fp;
int i, n, place = 0;
boardheader_t *bptr = NULL;
if (!(fp = fopen(BBSHOME "/etc/topboardman", "w")))
return;
fprintf(fp, "[1;44m排名[47;30m 看 板 目錄數 檔案數"
" byte數 [30m 總 分 板 主 [m\n");
for (i = 0; i < nbrds; i++) {
if ((n = getbnum(board[i].bname)) == 0)
continue;
bptr = getbcache(n);
if (strcmp(board[i].bname, bptr->brdname) != 0)
continue;
if (bptr->brdattr & (BRD_BAD | BRD_NOCOUNT))
continue;
/* 板主設定不列入記錄 */
if (bptr->brdattr & BRD_HIDE && !(bptr->brdattr & BRD_BMCOUNT))
continue;
if (board[i].ndir + board[i].nfile < 5)
break;
fprintf(fp, "%3d.[33m%15s[m %5d %7d %10d %6d [31m%-24.24s[m\n",
++place, board[i].bname, board[i].ndir, board[i].nfile, board[i].k
,board[i].k / 100 + board[i].nfile + board[i].ndir
,bptr->BM);
}
fclose(fp);
}
static boardinfo_t board[MAX_BOARD];
static const char dirs[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 0};
int main(int argc, char* argv[])
{
boardinfo_t *biptr;
int nSorted, nb;
DIR *dirp;
struct dirent *de;
int i, fd, checkrebuild = 0;
char *fname, fpath[PATHLEN];
nice(10);
while ((i = getopt(argc, argv, "xh")) != -1) {
switch (i) {
case 'x':
checkrebuild = 1;
break;
case 'h':
printf("NAME\n"
" mandex - 精華區索引程式 (man index)\n"
"\n"
"SYNOPSIS\n"
" mandex [-x] [-v] [board] ...\n"
"\n"
"DESCRIPTION\n"
"精華區索引 (man index)\n\n"
"-x 只有含有 .rebuild的目錄才重製\n"
"-v 顯示全部路徑\n"
"board 全部的板 (default to all)\n\n");
return 0;
}
}
argc -= optind;
argv += optind;
chdir(BBSHOME);
attach_SHM();
resolve_boards();
/* process boards given in arguments */
if (argc > 0) {
for (i = 0; i < argc; i++)
man_index(argv[i]);
return 0;
}
/* process all boards */
if (checkrebuild && (fd = open("man/.rank.cache", O_RDONLY)) >= 0) {
read(fd, board, sizeof(board));
close(fd);
qsort(board, MAX_BOARD, sizeof(boardinfo_t), sortbyname);
for (nb = 0; board[nb].bname[0] != 0; ++nb);
nSorted = nb;
} else {
memset(board, 0, sizeof(board));
checkrebuild = 0;
nSorted = nb = 0;
}
for (i = 0; dirs[i] != 0; ++i) {
snprintf(fpath, sizeof(fpath), "man/boards/%c", dirs[i]);
if (!(dirp = opendir(fpath))) {
printf("## unable to enter [man/boards/%c]\n", dirs[i]);
exit(-1);
}
while ((de = readdir(dirp))) {
fname = de->d_name;
if (fname[0] == '.')
continue;
if (checkrebuild) {
sprintf(fpath, "man/boards/%c/%s/.rebuild", dirs[i], fname);
if (access(fpath, 0) < 0) {
printf("skip no modify board %s\n", fname);
continue;
}
unlink(fpath);
}
man_index(fname);
if (curr_brdinfo.k) {
if (!(biptr = bsearch(fname, board, nSorted, sizeof(boardinfo_t), sortbyname)))
biptr = &board[nb++];
memcpy(biptr, &curr_brdinfo, sizeof(boardinfo_t));
}
}
closedir(dirp);
}
qsort(board, nb, sizeof(boardinfo_t), k_cmp);
output_chart(board, nb);
unlink(BBSHOME "/man/.rank.cache");
if ((fd = open(BBSHOME "/man/.rank.cache",
O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0660)) >= 0) {
write(fd, board, sizeof(board));
close(fd);
}
return 0;
}