summaryrefslogtreecommitdiffstats
path: root/mbbsd/fav.c
diff options
context:
space:
mode:
Diffstat (limited to 'mbbsd/fav.c')
-rw-r--r--mbbsd/fav.c252
1 files changed, 197 insertions, 55 deletions
diff --git a/mbbsd/fav.c b/mbbsd/fav.c
index 18d80353..5ba7c081 100644
--- a/mbbsd/fav.c
+++ b/mbbsd/fav.c
@@ -1,6 +1,38 @@
/* $Id$ */
#include "bbs.h"
+/**
+ * Structure
+ * =========
+ * fav4 的主要架構如下:
+ *
+ * fav_t - 用來裝各種 entry(fav_type_t) 的 directory
+ * 進入我的最愛時,看到的東西就是根據 fav_t 生出來的。
+ * 裡面紀錄者,這一個 level 中有多少個看板、目錄、分隔線。(favh)
+ * 是一個 array (with pre-allocated buffer)
+ *
+ * fav_type_t - fav entry 的 base class
+ * 存取時透過 type 變數來得知正確的型態。
+ *
+ * fav_board_t / fav_line_t / fav_folder_t - derived class
+ * 詳細情形請參考 fav.h 中的定義。
+ * 以 cast_(board|line|folder)_t 來將一個 fav_type_t 作動態轉型。
+ *
+ * Policy
+ * ======
+ * 為了避免過度的資料搬移,當將一個 item 從我的最愛中移除時,只將他的
+ * FAVH_FAV flag 移除。而沒有這個 flag 的 item 也不被視為我的最愛。
+ *
+ * 我的最愛中,沒設 FAVH_FAV 的資料,將在某些時候,如寫入檔案時,呼叫
+ * rebuild_fav 清除乾淨。
+ *
+ * Others
+ * ======
+ * 站長搬移看板所用的 t ,因為不能只存在 nbrd 裡面,又不然再弄出額外的空間,
+ * 所以當站長不在我的最愛按了 t ,會把這個記錄暫存在 fav 中
+ * (FAVH_ADM_TAG == 1, FAVH_FAV == 0)。
+ */
+
#ifdef MEM_CHECK
static int memcheck;
#endif
@@ -17,7 +49,10 @@ static fav_t *fav_tmp;
//static int fav_tmp_snum; /* the sequence number in favh in fav_t */
-/* for casting */
+/**
+ * cast_(board|line|folder) 一族用於將 base class 作轉型
+ * (不檢查實際 data type)
+ */
inline static fav_board_t *cast_board(fav_type_t *p){
return (fav_board_t *)p->fp;
}
@@ -30,20 +65,32 @@ inline static fav_folder_t *cast_folder(fav_type_t *p){
return (fav_folder_t *)p->fp;
}
+/**
+ * 傳回指定的 fp(dir) 中的 fp->DataTail, 第一個沒用過的位置的 index
+ */
inline static int get_data_tail(fav_t *fp){
return fp->DataTail;
}
+/**
+ * 傳回指定 dir 中所用的 entry 的總數 (只算真的在裡面,而不算已被移除的)
+ */
inline int get_data_number(fav_t *fp){
return fp->nBoards + fp->nLines + fp->nFolders;
}
+/**
+ * 傳回目前所在的 dir pointer
+ */
inline fav_t *get_current_fav(void){
if (fav_stack_num == 0)
return NULL;
return fav_stack[fav_stack_num - 1];
}
+/**
+ * 將 ft(entry) cast 成一個 dir
+ */
inline fav_t *get_fav_folder(fav_type_t *ft){
return cast_folder(ft)->this_folder;
}
@@ -52,6 +99,9 @@ inline int get_item_type(fav_type_t *ft){
return ft->type;
}
+/**
+ * 將一個指定的 dir pointer 存下來,之後可用 fav_get_tmp_fav 來存用
+ */
inline static void fav_set_tmp_folder(fav_t *fp){
fav_tmp = fp;
}
@@ -60,6 +110,9 @@ inline static fav_t *fav_get_tmp_fav(void){
return fav_tmp;
}
+/**
+ * 將 fp(dir) 記的數量中,扣除一單位 ft(entry)
+ */
static void fav_decrease(fav_t *fp, fav_type_t *ft){
switch (get_item_type(ft)){
case FAVT_BOARD:
@@ -75,6 +128,9 @@ static void fav_decrease(fav_t *fp, fav_type_t *ft){
fav_number--;
}
+/**
+ * 將 fp(dir) 記的數量中,增加一單位 ft(entry)
+ */
static void fav_increase(fav_t *fp, fav_type_t *ft)
{
switch (get_item_type(ft)){
@@ -98,6 +154,9 @@ inline static int get_folder_num(fav_t *fp) {
return fp->nFolders;
}
+/**
+ * get_(folder|line)_id 傳回 fp 中一個新的 folder/line id
+ */
inline static int get_folder_id(fav_t *fp) {
return fp->folderID;
}
@@ -110,18 +169,21 @@ inline static int get_line_num(fav_t *fp) {
return fp->nLines;
}
-/* bool:
- * 0: unset 1: set 2: opposite */
+/**
+ * 設定某個 flag。
+ * @bit: 目前所有 flags 有: FAVH_FAV, FAVH_TAG, FAVH_UNREAD, FAVH_ADM_TAG
+ * @param bool: FALSE: unset, TRUE: set, EXCH: opposite
+ */
void set_attr(fav_type_t *ft, int bit, char bool){
- if (bool == 2)
+ if (bool == EXCH)
ft->attr ^= bit;
- else if (bool == 1)
+ else if (bool == TRUE)
ft->attr |= bit;
else
ft->attr &= ~bit;
}
-int is_set_attr(fav_type_t *ft, char bit){
+inline int is_set_attr(fav_type_t *ft, char bit){
return ft->attr & bit;
}
@@ -151,17 +213,15 @@ static char *get_item_class(fav_type_t *ft)
return NULL;
}
-inline static void fav_set_memcheck(int n) {
#ifdef MEM_CHECK
+inline static void fav_set_memcheck(int n) {
memcheck = n;
-#endif
}
inline static int fav_memcheck(void) {
-#ifdef MEM_CHECK
return memcheck;
-#endif
}
+#endif
/* ---*/
static int get_type_size(int type)
@@ -184,7 +244,10 @@ inline static void* fav_malloc(int size){
return p;
}
-/* allocate the header(fav_type_t) and item it self. */
+/**
+ * allocate header(fav_type_t, base class) 跟 fav_*_t (derived class)
+ * @return 新 allocate 的空間
+ */
static fav_type_t *fav_item_allocate(int type)
{
int size = 0;
@@ -198,7 +261,9 @@ static fav_type_t *fav_item_allocate(int type)
return ft;
}
-/* symbolic link */
+/**
+ * 只複製 fav_type_t
+ */
inline static void
fav_item_copy(fav_type_t *target, const fav_type_t *source){
target->type = source->type;
@@ -210,17 +275,16 @@ inline fav_t *get_fav_root(void){
return fav_stack[0];
}
-char current_fav_at_root(void) {
- return get_current_fav() == get_fav_root();
-}
-
-/* is it an valid entry */
+/**
+ * 是否為有效的 entry
+ */
inline int valid_item(fav_type_t *ft){
return ft->attr & FAVH_FAV;
}
-/* return: the exact number after cleaning
- * reset the line number, board number, folder number, and total number (number)
+/**
+ * 清除 fp(dir) 中無效的 entry/dir,如果 clean_invisible == true,該 user
+ * 看不見的看板也會被清除。
*/
static void rebuild_fav(fav_t *fp, int clean_invisible)
{
@@ -312,9 +376,13 @@ void fav_sort_by_class(void)
qsort(get_current_fav()->favh, get_data_number(get_current_fav()), sizeof(fav_type_t), favcmp_by_class);
}
-/*
+/**
* The following is the movement operations in the user interface.
*/
+
+/**
+ * 目錄層數是否達到最大值 FAV_MAXDEPTH
+ */
inline int fav_stack_full(void){
return fav_stack_num >= FAV_MAXDEPTH;
}
@@ -349,7 +417,6 @@ void fav_folder_out(void)
fav_stack_pop();
}
-/* load from the rec file */
static void read_favrec(int fd, fav_t *fp)
{
int i;
@@ -386,6 +453,9 @@ static void read_favrec(int fd, fav_t *fp)
}
}
+/**
+ * 從記錄檔中 load 出我的最愛。
+ */
int fav_load(void)
{
int fd;
@@ -398,7 +468,9 @@ int fav_load(void)
if (!dashf(buf)) {
fp = (fav_t *)fav_malloc(sizeof(fav_t));
fav_stack_push_fav(fp);
+#ifdef MEM_CHECK
fav_set_memcheck(MEM_CHECK);
+#endif
return 0;
}
@@ -408,7 +480,9 @@ int fav_load(void)
read_favrec(fd, fp);
fav_stack_push_fav(fp);
close(fd);
+#ifdef MEM_CHECK
fav_set_memcheck(MEM_CHECK);
+#endif
return 0;
}
@@ -435,6 +509,10 @@ static void write_favrec(int fd, fav_t *fp)
}
}
+/**
+ * 把記錄檔 save 進我的最愛。
+ * @note fav_cleanup() 會先被呼叫。
+ */
int fav_save(void)
{
int fd;
@@ -454,24 +532,22 @@ int fav_save(void)
return -1;
write_favrec(fd, fp);
close(fd);
- if (dashs(buf) == 4) {
- time_t now = time(NULL);
- log_file(BBSHOME "/dirty.hack", LOG_CREAT | LOG_VF,
- "%s %s", cuser.userid, ctime(&now));
- return -1;
- }
Rename(buf, buf2);
return 0;
}
-/* It didn't need to remove it self, just remove all the attributes.
- * It'll be remove when it save to the record file. */
-static void fav_free_item(fav_type_t *ft)
+/**
+ * remove ft (設為 invalid,實際上會等到 save 時才清除)
+ */
+static inline void fav_free_item(fav_type_t *ft)
{
set_attr(ft, 0xFFFF, FALSE);
}
+/**
+ * delete ft from fp
+ */
static int fav_remove(fav_t *fp, fav_type_t *ft)
{
fav_free_item(ft);
@@ -479,7 +555,9 @@ static int fav_remove(fav_t *fp, fav_type_t *ft)
return 0;
}
-/* free the mem of whole fav tree */
+/**
+ * free the mem of fp recursively
+ */
static void fav_free_branch(fav_t *fp)
{
int i;
@@ -505,6 +583,9 @@ static void fav_free_branch(fav_t *fp)
fp = NULL;
}
+/**
+ * free the mem of the whole fav tree recursively
+ */
void fav_free(void)
{
fav_free_branch(get_fav_root());
@@ -513,6 +594,10 @@ void fav_free(void)
fav_stack_num = 0;
}
+/**
+ * 從目前的 dir 中找出特定類別 (type)、id 為 id 的 entry。
+ * 找不到傳回 NULL
+ */
static fav_type_t *get_fav_item(short id, int type)
{
int i;
@@ -529,11 +614,17 @@ static fav_type_t *get_fav_item(short id, int type)
return NULL;
}
+/**
+ * 從目前的 dir 中 remove 特定類別 (type)、id 為 id 的 entry。
+ */
void fav_remove_item(short id, char type)
{
fav_remove(get_current_fav(), get_fav_item(id, type));
}
+/**
+ * get*(bid) 傳回目前的 dir 中該類別 id == bid 的 entry。
+ */
fav_type_t *getadmtag(short bid)
{
int i;
@@ -599,12 +690,19 @@ int fav_getid(fav_type_t *ft)
return -1;
}
-/* suppose we don't add too much fav_type_t at the same time. */
+inline static int is_maxsize(void){
+ return fav_number >= MAX_FAV;
+}
+
+/**
+ * 每次一個 dir 滿時,這個 function 會將 buffer 大小調大 FAV_PRE_ALLOC 個,
+ * 直到上限為止。
+ */
static int enlarge_if_full(fav_t *fp)
{
fav_type_t * p;
/* enlarge the volume if need. */
- if (fav_number >= MAX_FAV)
+ if (is_maxsize)
return -1;
if (fp->DataTail < fp->nAllocs)
return 1;
@@ -620,10 +718,9 @@ static int enlarge_if_full(fav_t *fp)
return 0;
}
-inline static int is_maxsize(void){
- return fav_number >= MAX_FAV;
-}
-
+/**
+ * 將一個新的 entry item 加入 fp 中
+ */
static int fav_add(fav_t *fp, fav_type_t *item)
{
if (enlarge_if_full(fp) < 0)
@@ -633,41 +730,50 @@ static int fav_add(fav_t *fp, fav_type_t *item)
return 0;
}
-/* just move, in one folder */
-static void move_in_folder(fav_t *fav, int from, int to)
+static void move_in_folder(fav_t *fav, int src, int dst)
{
int i, count;
fav_type_t tmp;
- /* Find real locations of from and to in fav->favh[] */
- for(count = i = 0; count <= from; i++)
+ /* Find real locations of src and dst in fav->favh[] */
+ for(count = i = 0; count <= src; i++)
if (valid_item(&fav->favh[i]))
count++;
- from = i - 1;
- for(count = i = 0; count <= to; i++)
+ src = i - 1;
+ for(count = i = 0; count <= dst; i++)
if (valid_item(&fav->favh[i]))
count++;
- to = i - 1;
+ dst = i - 1;
- fav_item_copy(&tmp, &fav->favh[from]);
+ fav_item_copy(&tmp, &fav->favh[src]);
- if (from < to) {
- for(i = from; i < to; i++)
+ if (src < dst) {
+ for(i = src; i < dst; i++)
fav_item_copy(&fav->favh[i], &fav->favh[i + 1]);
}
- else { // to < from
- for(i = from; i > to; i--)
+ else { // dst < src
+ for(i = src; i > dst; i--)
fav_item_copy(&fav->favh[i], &fav->favh[i - 1]);
}
- fav_item_copy(&fav->favh[to], &tmp);
+ fav_item_copy(&fav->favh[dst], &tmp);
}
+/**
+ * 將目前目錄中第 src 個 entry 移到 dst。
+ * @note src/dst 是 user 實際上看到的位置,也就是不包含 invalid entry。
+ */
void move_in_current_folder(int from, int to)
{
move_in_folder(get_current_fav(), from, to);
}
-/* the following defines the interface of add new fav_XXX */
+/**
+ * the following defines the interface of add new fav_XXX
+ */
+
+/**
+ * allocate 一個 folder entry
+ */
inline static fav_t *alloc_folder_item(void){
fav_t *fp = (fav_t *)fav_malloc(sizeof(fav_t));
fp->nAllocs = FAV_PRE_ALLOC;
@@ -686,7 +792,10 @@ static fav_type_t *init_add(fav_t *fp, int type)
return ft;
}
-/* if place < 0, just put the item to the tail */
+/**
+ * 新增一分隔線
+ * @return 加入的 entry 指標
+ */
fav_type_t *fav_add_line(void)
{
fav_t *fp = get_current_fav();
@@ -695,6 +804,10 @@ fav_type_t *fav_add_line(void)
return init_add(fp, FAVT_LINE);
}
+/**
+ * 新增一目錄
+ * @return 加入的 entry 指標
+ */
fav_type_t *fav_add_folder(void)
{
fav_t *fp = get_current_fav();
@@ -710,17 +823,27 @@ fav_type_t *fav_add_folder(void)
return ft;
}
+/**
+ * 將指定看板加入目前的目錄。
+ * @return 加入的 entry 指標
+ * @note 不允許同一個板被加入兩次
+ */
fav_type_t *fav_add_board(int bid)
{
fav_t *fp = get_current_fav();
- fav_type_t *ft = init_add(fp, FAVT_BOARD);
+ fav_type_t *ft = getboard(bid);
+ if (ft != NULL)
+ return ft;
+ ft = init_add(fp, FAVT_BOARD);
if (ft == NULL)
return NULL;
cast_board(ft)->bid = bid;
return ft;
}
-/* for administrator to move/administrate board */
+/**
+ * for administrator to move/administrate board
+ */
fav_type_t *fav_add_admtag(int bid)
{
fav_t *fp = get_fav_root();
@@ -731,7 +854,7 @@ fav_type_t *fav_add_admtag(int bid)
if (ft == NULL)
return NULL;
// turn on FAVH_ADM_TAG
- set_attr(ft, FAVH_ADM_TAG, 1);
+ set_attr(ft, FAVH_ADM_TAG, TRUE);
fav_add(fp, ft);
cast_board(ft)->bid = bid;
return ft;
@@ -741,6 +864,11 @@ fav_type_t *fav_add_admtag(int bid)
/* everything about the tag in fav mode.
* I think we don't have to implement the function 'cross-folder' tag.*/
+/**
+ * 將目前目錄下,由 type & id 指定的 entry 標上/取消 tag
+ * @param bool 同 set_attr
+ * @note 若同一個目錄不幸有同樣的東西,只有第一個會作用。
+ */
void fav_tag(short id, char type, char bool) {
fav_type_t *ft = get_fav_item(id, type);
if (ft != NULL)
@@ -825,6 +953,9 @@ static void fav_dosomething_all_tagged_item(int (*act)(fav_t *))
fav_do_recursively(get_fav_root(), act);
}
+/**
+ * fav_*_all_tagged_item 在整個我的最愛上對已標上 tag 的 entry 做某件事。
+ */
void fav_remove_all_tagged_item(void)
{
fav_dosomething_all_tagged_item(fav_remove_tagged_item);
@@ -848,11 +979,17 @@ inline static int remove_tags(fav_t *fp)
return 0;
}
+/**
+ * 移除我的最愛所有的 tags
+ */
void fav_remove_all_tag(void)
{
fav_dosomething_all_tagged_item(remove_tags);
}
+/**
+ * 設定 folder 的中文名稱
+ */
void fav_set_folder_title(fav_type_t *ft, char *title)
{
if (get_item_type(ft) != FAVT_FOLDER)
@@ -863,6 +1000,11 @@ void fav_set_folder_title(fav_type_t *ft, char *title)
#define BRD_OLD 0
#define BRD_NEW 1
#define BRD_END 2
+/**
+ * 如果 user 開啟 FAVNEW_FLAG 的功能:
+ * mode == 1: update 看板,並將新看板加入我的最愛。
+ * mode == 0: update 資訊但不加入。
+ */
void updatenewfav(int mode)
{
/* mode: 0: don't write to fav 1: write to fav */