summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/brc.txt96
-rw-r--r--include/proto.h13
-rw-r--r--mbbsd/bbs.c2
-rw-r--r--mbbsd/board.c13
-rw-r--r--mbbsd/brc.c160
-rw-r--r--mbbsd/var.c4
6 files changed, 153 insertions, 135 deletions
diff --git a/docs/brc.txt b/docs/brc.txt
index 0a62f13c..315a1fbc 100644
--- a/docs/brc.txt
+++ b/docs/brc.txt
@@ -1,5 +1,6 @@
BRC documentation by scw 08/05/2003
+ 06/12/2007 revised by kcwu
源起:
這篇文章主要是介紹 brc_* 的函式,這組函式是 pttbbs 用來紀錄文章已讀/未讀
@@ -17,20 +18,19 @@ BRC 是什麼?如何運作?
它的特點是用的空間極少。可以在 24k 以內的空間記下一個人在全站的文章已讀/
未讀。當然,這樣的方法不可能真正完美,但是對於使用上已經足夠了。為什麼說是不
完美呢?這跟紀錄的儲存方式有關。
- 紀錄檔在 home/[first charactor of id]/[id]/.boardrc。檔案格式如下:
+ 紀錄檔在 home/[first charactor of id]/[id]/.brc2。檔案格式如下:
FILE := RECORDS ;
RECORDS := RECORDS RECORD | ;
- RECORD := BOARD_NAME BRC_DATA ;
+ RECORD := BRC_BID BRC_DATA ;
BRC_DATA := BRC_NUM BRC_LIST ;
BRC_LIST := NUM NUM ... NUM ; (共 BRC_NUM 個 NUM)
- BOARD_NAME 是 15 bytes 的板名 (#define BRC_STRLEN 15)
- BRC_NUM 是對這個板的儲存量,1 byte 以 binary 方式儲存,其值 <= MAX_NUM (80)
- BRC_LIST 是對這個板的紀錄,剛好有 BRC_NUM 個 4 bytes integers。
+ BRC_BID 是 board bid, sizeof(brcbid_t)=2 bytes.
+ BRC_NUM 是對這個板的儲存量,sizeof(brcnbrd_t)=2 bytes 以 binary 方式儲存,其值 <= MAX_NUM (80)
+ BRC_LIST 是對這個板的紀錄,剛好有 BRC_NUM 個 sizeof(time4_t)=4 bytes integers。
另外在 24576 bytes (#define BRC_MAXSIZE 24576) 之外的資料不會被用到。
- 在下面會看到,BOARD_NAME 不用另外儲存(已經放在user的全域資料裡了),其他
- 兩項, BRC_NUM 跟 BRC_LIST 都會放在相應的全域變數中, brc_num & brc_list 。
+ 在下面會看到,BRC_BID 跟 BRC_NUM 跟 BRC_LIST 都會放在相應的變數中, brc_currbid & brc_num & brc_list 。
判定一個檔案是否已經讀過的方法是在 brc_list 中搜尋檔案建立的時間,也就是
檔名 M.xxxxxxxxxx.A.yyy 中 xxxxxxxxx 的那個數字。如果這個數字有在 brc_list 中
出現就是已讀,要不如果 brc_list 中所有的數字都比這個檔案的建立時間大(也就是
@@ -40,7 +40,7 @@ BRC 是什麼?如何運作?
這樣可以看出為什麼這個方法不是真正完美但是已經足夠。不完美的原因有三個:
首先, brc_num <= 80 也就是 brc_list 最多存八十個數,這表示除了很久以前的文章
外,只會有八十篇是已讀的。第二就是所有一年前的文章都會被判為已讀。最後,如果一
- 個人看的板太多,讓 .boardrc 大小超過 BRC_MAXSIZE 有些板的紀錄就會不見( 24576
+ 個人看的板太多,讓 .brc2 大小超過 BRC_MAXSIZE 有些板的紀錄就會不見( 24576
bytes 最少可以存 73 個板的資料,這還是用全部板 brc_num 都是 80 計算的)。但這
三個小缺點影響應該不大吧?
@@ -48,53 +48,38 @@ BRC 實作
interface: (in proto.h)
- int brc_unread(char *fname, int bnum, int *blist);
+ int brc_initialize();
+ void brc_finalize();
+
+ int brc_unread(int bid, char *fname, int bnum, int *blist);
判斷一篇文章是否已讀。
傳入值:文章檔名 (fname) 以及 brc_num (bnum) 和 brc_list (blist)。
傳回值:如果由 bnum 和 blist 判斷本篇文章未讀傳回 1。
否則傳回 0。
額外效果:無。
- int brc_initial(char *boardname);
+ int brc_initial_board(char *boardname);
初始化在一個板的已讀未讀狀態。
傳入值:要初始化的板名。
傳回值:若找到之前的紀錄傳回新的 brc_num,否則傳回 0。
額外效果:如果傳入的看板就是目前看板會直接傳回 brc_num, 不做別的事。否則
- 本函式會先將目前的 brc data 寫入 .boardrc 中,更改 currboard ,取得
+ 本函式會先將目前的 brc data 寫回 brc_buf 中,更改 currboard ,取得
currbid 和 currbrdattr 後再讀取並更新 brc_num 及 brc_list。如果在使用者
- 的 .boardrc 中沒有關於這個板的紀錄,會設定 brc_num = 1,brc_list[0] = 1
+ 的 brc_buf 中沒有關於這個板的紀錄,會設定 brc_num = 1,brc_list[0] = 1
並傳回 0。
void brc_update();
- 將目前的 brc data 寫入 .boardrc 中。
+ 將目前的 brc data 寫入 brc_buf 中。
額外效果:如果 brc data 未被更改或使用者權限不足則不會有動作。
void brc_addlist(char *fname);
- 將文章標示為已讀。
+ 將文章標示為已讀。使用前需先 brc_initial_board()
傳入值:要標示為已讀的文章檔名。
- global variables: (in var.c)
-
- int brc_num;
- brc_list 中的有效數字個數。
-
- int brc_list[BRC_MAXNUM];
- 已讀文章的存檔時間。
-
- (in var.h)
- extern int brc_num;
- extern int brc_list[BRC_MAXNUM];
-
- constant definition: (in board.c)
-
- #define BRC_STRLEN 15 /* Length of board name */
- 板名最大長度。
+ constant definition:
#define BRC_MAXSIZE 24576
- .boardrc 的有效大小。
-
- #define BRC_ITEMSIZE (BRC_STRLEN + 1 + BRC_MAXNUM * sizeof( int ))
- 每個 record 的最大大小。
+ .brc2 的有效大小。
#define BRC_MAXNUM 80
brc_num 的最大值。
@@ -105,47 +90,34 @@ BRC 實作
brc_list 中值的下限,時間在此之前的一律當作已讀。會在 init_brdbuf 中被設
定為 login_start_time - 365 * 86400。
- static int brc_changed = 0;
- 從上次讀取 .boardrc 到當時為止,brc_num 與 brc_list 是否改變過(為減少寫
- 檔的次數)。
-
static char brc_buf[BRC_MAXSIZE];
- 呼叫 read_brc_buf 後 .boardrc 的前 BRC_MAXSIZE bytes 會被置入這個 buffer
- 中。
+ 呼叫 read_brc_buf 後 .brc2 的前 BRC_MAXSIZE bytes 會被置入這個 buffer 中。
static int brc_size;
呼叫 read_brc_buf 後 brc_buf 中的有效字元數。
- static char brc_name[BRC_STRLEN];
- 目前 brc data 的板名。 (不知道可否用 currboard 代替? by scw)
+ static int brc_changed = 0;
+ 從上次讀取 .brc2 到當時為止,brc_num 與 brc_list 是否改變過。
- static char * fn_boardrc = ".boardrc";
- brc 設定檔名。
+ static int brc_currbid;
- char * brc_buf_addr=brc_buf;
- unused variable
-
- private funcions: (in board.c)
+ static int brc_num;
+ brc_list 中的有效數字個數。
+
+ static int brc_list[BRC_MAXNUM];
+ 已讀文章的存檔時間。
+
static void read_brc_buf();
- 從 .boardrc 中讀取最多 BRC_MAXSIZE bytes 並存入 brc_buf 中,將存入的字元
+ 從 .brc2 中讀取最多 BRC_MAXSIZE bytes 並存入 brc_buf 中,將存入的字元
數存在 brc_size 中。
- static char * brc_getrecord(char *ptr, char *name, int *pnum, int *list);
- 從 buffer 中讀取一項紀錄。 (通常在 read_brc_bufi() 之後使用)
- 傳入值:ptr 為要讀取的 buffer, name, pnum, 和 list 分別寫入讀到的資料。
- 傳回值:指向讀出的 record 下一個字元的指標。
- 額外效果:name 會被存入最多 BRC_MAXLEN 個字元,為讀到的 record 的板名。
- pnum 會被存入讀到的 brc_num,list 會被寫入 *pnum 的整數,為 brc_list
- 的資料。
-
- static char * brc_putrecord(char *ptr, char *name, int num, int *list);
+ static char * brc_putrecord(char *ptr, char *endp, brcbid_t bid, brcnbrd_t num, const time4_t *list);
與 brc_getrecord() 的作用正好相反,將資料寫入 puffer 中。
- 傳入值:ptr 只向要寫入的 buffer,name, num, list 分別是要寫入的資料。
+ 傳入值:ptr 指向要寫入的 buffer,bid, num, list 分別是要寫入的資料。
傳回值:指向寫入的 record 下一個字元的指標。
- 額外效果:若資料是合法的 (num > 0 && list[0] > brc_expire_time) ptr 會被
- 寫入 BRC_ITEMSIZE bytes 的資料。在 list 中比 brc_expire_time 的數字不會
- 被寫入(所以寫入的 brc_num 可能比 num 小)。
+ 額外效果:若資料是合法的 (num > 0 && list[0] > brc_expire_time) 且空間足夠,
+ 資料會被寫入 ptr, endp 之間。
static int brc_unread_time(time_t ftime, int bnum, int *blist);
跟 brc_unread() 類似,只是傳入的是檔案建立的時間。
diff --git a/include/proto.h b/include/proto.h
index c5afa9b2..eef17976 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -100,15 +100,16 @@ void sigfree(int);
/* brc */
int brc_initialize(void);
void brc_finalize(void);
-int brc_unread(const char *fname, int bnum, const time4_t *blist);
-int brc_unread_time(time4_t ftime, int bnum, const time4_t *blist);
+
+int brc_unread(int bid, const char *fname);
+int brc_unread_time(int bid, time4_t ftime);
int brc_initial_board(const char *boardname);
-void brc_update(void);
-int brc_read_record(int bid, int *num, time4_t *list);
-time4_t * brc_find_record(int bid, int *num);
-void brc_trunc(int bid, time4_t ftime);
void brc_addlist(const char* fname);
+void brc_update(void);
+
+void brc_toggle_all_read(int bid, int is_all_read);
+
/* cache */
#define demoney(money) deumoney(usernum, money)
#define search_ulist(uid) search_ulistn(uid, 1)
diff --git a/mbbsd/bbs.c b/mbbsd/bbs.c
index cf7ad993..ba75286c 100644
--- a/mbbsd/bbs.c
+++ b/mbbsd/bbs.c
@@ -303,7 +303,7 @@ readdoent(int num, fileheader_t * ent)
char *mark, *title,
color, special = 0, isonline = 0, recom[8];
userinfo_t *uentp;
- type = brc_unread(ent->filename, brc_num, brc_list) ? '+' : ' ';
+ type = brc_unread(currbid, ent->filename) ? '+' : ' ';
if ((currmode & MODE_BOARD) && (ent->filemode & FILE_DIGEST))
type = (type == ' ') ? '*' : '#';
else if (currmode & MODE_BOARD || HasUserPerm(PERM_LOGINOK)) {
diff --git a/mbbsd/board.c b/mbbsd/board.c
index 8a228287..e9267703 100644
--- a/mbbsd/board.c
+++ b/mbbsd/board.c
@@ -133,9 +133,7 @@ HasBoardPerm(boardheader_t *bptr)
static int
check_newpost(boardstat_t * ptr)
{ /* Ptt 改 */
- int tbrc_num;
time4_t ftime;
- time4_t *tbrc_list;
ptr->myattr &= ~NBRD_UNREAD;
if (B_BH(ptr)->brdattr & (BRD_GROUPBOARD | BRD_SYMBOLIC))
@@ -155,8 +153,7 @@ check_newpost(boardstat_t * ptr)
if (ftime > now + 10)
ftime = B_LASTPOSTTIME(ptr) = now - 1;
- tbrc_list = brc_find_record(ptr->bid, &tbrc_num);
- if ( brc_unread_time(ftime, tbrc_num, tbrc_list) )
+ if ( brc_unread_time(ptr->bid, ftime) )
ptr->myattr |= NBRD_UNREAD;
return 1;
@@ -451,7 +448,7 @@ unread_position(char *dirfile, boardstat_t * ptr)
while (num > 0) {
lseek(fd, (off_t) (num * sizeof(fh)), SEEK_SET);
if (read(fd, fname, FNLEN) <= 0 ||
- !brc_unread(fname, brc_num, brc_list))
+ !brc_unread(ptr->bid, fname))
break;
num -= step;
if (step < 32)
@@ -462,7 +459,7 @@ unread_position(char *dirfile, boardstat_t * ptr)
while (num < total) {
lseek(fd, (off_t) (num * sizeof(fh)), SEEK_SET);
if (read(fd, fname, FNLEN) <= 0 ||
- brc_unread(fname, brc_num, brc_list))
+ brc_unread(ptr->bid, fname))
break;
num++;
}
@@ -1129,9 +1126,9 @@ choose_board(int newflag)
break;
if (ch == 'v') {
ptr->myattr &= ~NBRD_UNREAD;
- brc_trunc(ptr->bid, now);
+ brc_toggle_all_read(ptr->bid, 1);
} else {
- brc_trunc(ptr->bid, 1);
+ brc_toggle_all_read(ptr->bid, 0);
ptr->myattr |= NBRD_UNREAD;
}
show_brdlist(head, 0, newflag);
diff --git a/mbbsd/brc.c b/mbbsd/brc.c
index 8c4b86da..8360cedc 100644
--- a/mbbsd/brc.c
+++ b/mbbsd/brc.c
@@ -6,7 +6,7 @@
*/
#ifndef BRC_MAXNUM
-#define BRC_STRLEN 15 /* Length of board name */
+#define BRC_STRLEN 15 /* Length of board name, for old brc */
#define BRC_MAXSIZE 24576 /* Effective size of brc rc file, 8192 * 3 */
#define BRC_MAXNUM 80 /* Upper bound of brc_num, size of brc_list */
#endif
@@ -26,45 +26,38 @@ typedef unsigned short brcnbrd_t;
* brc_num 1 byte, binary integer
* brc_list brc_num * sizeof(int) bytes, brc_num binary integer(s) */
+static char brc_initialized = 0;
static time4_t brc_expire_time;
/* Will be set to the time one year before login. All the files created
* before then will be recognized read. */
-static int brc_changed = 0;
+static int brc_changed = 0; /**< brc_list/brc_num changed */
/* The below two will be filled by read_brc_buf() and brc_update() */
static char *brc_buf = NULL;
static int brc_size;
static int brc_alloc;
+// read records for currbid
+static int brc_currbid;
+static int brc_num;
+static time4_t brc_list[BRC_MAXNUM];
+
static char * const fn_oldboardrc = ".boardrc";
static char * const fn_brc = ".brc2";
-#if 0
-/* unused after brc2 */
-static char *
-brc_getrecord(char *ptr, char *endp, brcbid_t *bid,
- brcnbrd_t *pnum, time4_t *list)
-{
- brcnbrd_t num;
- char *tmp;
-
- if (ptr + sizeof(brcbid_t) + sizeof(brcnbrd_t) > endp)
- return endp + 1; /* dangling, ignoring it */
- *bid = *(brcbid_t*)ptr; /* bid */
- ptr += sizeof(brcbid_t);
- num = *(brcnbrd_t*)ptr; /* brc_num */
- ptr += sizeof(brcnbrd_t);
- tmp = ptr + num * sizeof(time4_t); /* end of this record */
- if (tmp <= endp){
- memcpy(list, ptr, num * sizeof(time4_t)); /* brc_list */
- if (num > BRC_MAXNUM)
- num = BRC_MAXNUM;
- *pnum = num;
- }
- return tmp;
-}
-#endif
-
+/**
+ * find read records of bid in given buffer region
+ *
+ * @param[in] begin
+ * @param[in] endp
+ * @param bid
+ * @param[out] num number of records, which could be written for \a bid
+ * = brc_num if found
+ * = 0 or dangling size if not found
+ *
+ * @return address of record. \a begin <= addr < \a endp.
+ * 0 if not found
+ */
/* Returns the address of the record strictly between begin and endp with
* bid equal to the parameter. Returns 0 if not found.
* brcnbrd_t *num is an output parameter which will filled with brc_num
@@ -97,7 +90,7 @@ brc_findrecord_in(char *begin, char *endp, brcbid_t bid, brcnbrd_t *num)
return 0;
}
-time4_t *
+static time4_t *
brc_find_record(int bid, int *num)
{
char *p;
@@ -152,11 +145,13 @@ brc_enlarge_buf(void)
#endif
buffer = (char*)THE_MALLOC(brc_alloc);
+ assert(buffer);
memcpy(buffer, brc_buf, brc_alloc);
free(brc_buf);
brc_alloc += BRC_BLOCKSIZE;
brc_buf = (char*)malloc(brc_alloc);
+ assert(brc_buf);
memcpy(brc_buf, buffer, brc_alloc - BRC_BLOCKSIZE);
#ifdef DEBUG
@@ -179,6 +174,7 @@ brc_get_buf(int size){
if (brc_alloc > BRC_MAXSIZE)
brc_alloc = BRC_MAXSIZE;
brc_buf = (char*)malloc(brc_alloc);
+ assert(brc_buf);
}
static inline void
@@ -239,10 +235,13 @@ brc_insert_record(brcbid_t bid, brcnbrd_t num, const time4_t* list)
brc_changed = 0;
}
+/**
+ * write \a brc_num and \a brc_list back to \a brc_buf.
+ */
void
brc_update(){
- if (brc_changed && cuser.userlevel && brc_num > 0)
- brc_insert_record(currbid, brc_num, brc_list);
+ if (brc_currbid && brc_changed && cuser.userlevel && brc_num > 0)
+ brc_insert_record(brc_currbid, brc_num, brc_list);
}
/* return 1 if successfully read from old .boardrc file.
@@ -314,36 +313,65 @@ read_brc_buf(void)
}
void
+brc_release()
+{
+ if (brc_buf) {
+ free(brc_buf);
+ brc_buf = NULL;
+ }
+ brc_currbid = 0;
+ brc_num = 0;
+ brc_changed = 0;
+ brc_size = brc_alloc = 0;
+}
+
+void
brc_finalize(){
char brcfile[STRLEN];
char tmpfile[STRLEN];
- int fd;
- int ok=0;
+
brc_update();
setuserfile(brcfile, fn_brc);
snprintf(tmpfile, sizeof(tmpfile), "%s.tmp.%x", brcfile, getpid());
- if (brc_buf != NULL &&
- (fd = open(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) {
- if(write(fd, brc_buf, brc_size)==brc_size)
- ok=1;
- close(fd);
+ if (brc_buf != NULL) {
+ int fd = open(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd != -1) {
+ int ok=0;
+ if(write(fd, brc_buf, brc_size)==brc_size)
+ ok=1;
+ close(fd);
+ if(ok)
+ Rename(tmpfile, brcfile);
+ else
+ unlink(tmpfile);
+ }
}
- if(ok)
- Rename(tmpfile, brcfile);
+
+ brc_release();
+ brc_initialized = 0;
}
int
brc_initialize(){
- static char done = 0;
- if (done)
+ if (brc_initialized)
return 1;
- done = 1;
+ brc_initialized = 1;
brc_expire_time = login_start_time - 365 * 86400;
read_brc_buf();
return 0;
}
-int
+/**
+ * get the read records for bid
+ *
+ * @param bid
+ * @param[out] num number of record for \a bid. 1 <= \a num <= \a BRC_MAXNUM
+ * \a num = 1 if no records.
+ * @param[out] list the list of records, length \a num
+ *
+ * @return number of read record, 0 if no records
+ */
+static int
brc_read_record(int bid, int *num, time4_t *list){
char *ptr;
brcnbrd_t tnum;
@@ -358,12 +386,16 @@ brc_read_record(int bid, int *num, time4_t *list){
return 0;
}
+/**
+ * @return number of records in \a boardname
+ */
int
brc_initial_board(const char *boardname)
{
brc_initialize();
if (strcmp(currboard, boardname) == 0) {
+ assert(currbid == brc_currbid);
return brc_num;
}
@@ -372,16 +404,17 @@ brc_initial_board(const char *boardname)
if( currbid == 0 )
currbid = getbnum(DEFAULT_BOARD);
assert(0<=currbid-1 && currbid-1<MAX_BOARD);
+ brc_currbid = currbid;
currboard = bcache[currbid - 1].brdname;
currbrdattr = bcache[currbid - 1].brdattr;
- return brc_read_record(currbid, &brc_num, brc_list);
+ return brc_read_record(brc_currbid, &brc_num, brc_list);
}
-void
+static void
brc_trunc(int bid, time4_t ftime){
brc_insert_record(bid, 1, &ftime);
- if ( bid == currbid ){
+ if ( bid == brc_currbid ){
brc_num = 1;
brc_list[0] = ftime;
brc_changed = 0;
@@ -389,11 +422,21 @@ brc_trunc(int bid, time4_t ftime){
}
void
+brc_toggle_all_read(int bid, int is_all_read)
+{
+ if (is_all_read)
+ brc_trunc(bid, now);
+ else
+ brc_trunc(bid, 1);
+}
+
+void
brc_addlist(const char *fname)
{
int n, i;
time4_t ftime;
+ assert(currbid == brc_currbid);
if (!cuser.userlevel)
return;
@@ -426,30 +469,39 @@ brc_addlist(const char *fname)
}
int
-brc_unread_time(time4_t ftime, int bnum, const time4_t *blist)
+brc_unread_time(int bid, time4_t ftime)
{
- int n;
+ int i;
+ int bnum;
+ const time4_t *blist;
if (ftime <= brc_expire_time) /* too old */
return 0;
+ if (brc_currbid && bid == brc_currbid) {
+ blist = brc_list;
+ bnum = brc_num;
+ } else {
+ blist = brc_find_record(bid, &bnum);
+ }
+
if (bnum <= 0)
return 1;
- for (n = 0; n < bnum; n++) { /* using linear search */
- if (ftime > blist[n])
+ for (i = 0; i < bnum; i++) { /* using linear search */
+ if (ftime > blist[i])
return 1;
- else if (ftime == blist[n])
+ else if (ftime == blist[i])
return 0;
}
return 0;
}
int
-brc_unread(const char *fname, int bnum, const time4_t *blist)
+brc_unread(int bid, const char *fname)
{
int ftime;
ftime = atoi(&fname[2]); /* this will get the time of the file created */
- return brc_unread_time(ftime, bnum, blist);
+ return brc_unread_time(bid, ftime);
}
diff --git a/mbbsd/var.c b/mbbsd/var.c
index 52864a4f..39c87442 100644
--- a/mbbsd/var.c
+++ b/mbbsd/var.c
@@ -363,10 +363,6 @@ SHM_t *SHM;
boardheader_t *bcache;
userinfo_t *currutmp;
-/* brc.c */
-int brc_num;
-time4_t brc_list[BRC_MAXNUM];
-
/* read.c */
int TagNum; /* tag's number */
int TagBoard = -1; /* TagBoard = 0 : user's mailbox */