作者TKyo.bbs@cpu.tfcis.org (暗黑貴公子) 看板: plan
標題[更新 2]PTT's pmore.c 功能 patch for M3 more.c
時間動力核心 (2006/06/14 Wed 22:46:50) Updated: 2006/06/16
[前版前言]
1.創作本功能前, 已經先行知會 PTT (批踢踢實業坊) BBS 站長 in2
並獲得他允許 "創意創作" 而後, 自行依照其功能面搭配原本 more.c 程式碼創作
且未參考 pmore.c 任何程式碼
2.創作本功能後, 也已經知會 PTT (批踢踢實業坊) BBS pmore.c 原創者 piaip
並獲得他允許, 將 patch 原始碼交由 itoc 公佈
[本板前言]
本次更新版本, 完全取代先前發表之版本
[功能面簡介]
a.按鍵 :
Tab - 向右翻閱一次 4 列
Shift+Tab/Z/z - 向左翻閱一次 4 列
./> - 向右翻閱一次 1 列 (第一次移動 2 列)
,/< - 向左翻閱一次 1 列
b.第一次按 . 向右翻閱時, 由於有 < 提示符號的關係
如果只移動 1 列的話, 會讓使用者感覺不出來畫面有在移動, 因此才移動 2 列
c.PCMan/KKMan(尚未實驗) 不支援 Shift+Tab 按鍵, 會誤判為 Tab 按鍵
請用 z 和 Z 替代
[本次更新]
1.當 "一行字數 > 80 行" 時, 畫面再次整理動態移動及特別顯示
特別顯示 (Header 區域例外)
'\' - 為自動斷行符號
'>' - 文章位移後, 表示尚有文章未顯示
2.修正 :
擷取 Header 資訊時, 原先使用 f_map() 方式, <== 浪費了太多時間
故改為使用一般檔案 I/O 方式, 得知是否有 Header, 並適時插入分隔線
其他額外修正
------------------------------------------------------------------------------
:src/include/global.h
#define KEY_TAB 9 /* 和 Ctrl('I') 相同 */
+ #define KEY_STAB 90 /* 和 Z 相同 */
#define QUOTE_CHAR1 '>'
#define QUOTE_CHAR2 ':'
+ #define QUOTE_CHAR3 '='
+ #define QUOTE_CHAR4 '<'
+ #define QUOTE_CHAR5 '\\'
/* 新板本已將 LINE_HEADER 搬移至 global.h
給 more.c/bhttpd.c 使用 */
+ #define LINE_HEADER 3 /* 檔頭有三行 */
+ #define STR_HEADER {"作者", "標題", "時間"}
+ #define STR_HEADER2 {"發信人", "標 題", "發信站"}
------------------------------------------------------------------------------
:scr/include/theme.h
- #define FOOTER_MORE \
- COLOR1 " 瀏覽 P.%d (%d%%) " COLOR2 " (h)說明 [PgUp][PgDn][0][$]移動" \
- " (/n)搜尋 (C)暫存 (←q)結束 "
+ #define FOOTER_MORE \
+ COLOR1 " 瀏覽 P.%d (%d%%) " COLOR2 " (/n)搜尋 (h)說明 (←/q)離開%*s" \
+ "║列:%d - %d│行:%d - %d║ "
+ /* ----------------------------------------------------- */
+ /* 文章閱讀顏色 */
+ /* ----------------------------------------------------- */
+ #define COLOR_MORE_MASK "\033[7m" /* 比對正確 Color */
+ #define COLOR_MORE_OFFSET "\033[1;37m" /* 特別顯示符號顏色 */
+ #define COLOR_MORE_QUOTE "\033[1;32m" /* 第一層 QUOTE 顏色 1 */
+ #define COLOR_MORE_QUOTE2 "\033[35m" /* 第二層 QUOTE 顏色 2 */
+ #define COLOR_MORE_QUOTE3 "\033[32m" /* 第三層 QUOTE 顏色 3 */
------------------------------------------------------------------------------
:src/maple/visio.c
/*
新增兩函式 outa() 和 outax()
outa() - 原先設計給光棒介面中文正確斷行使用
outax() - 設計給 more.c 專用, 支援中文正確斷行及特殊 Ansi Code
並回傳該輸出多少 space
因應 outax(), 更新 outx(), 新增 out_extend_ansi_char() 給兩函式共用函式
*/
#ifdef SHOW_USER_IN_TEXT
static int
out_extend_ansi_char(ch)
uschar ch;
{
char buf[20];
switch (ch)
{
case 's': /* **s 顯示 ID */
sprintf(buf, "%s", cuser.userid);
break;
case 'n': /* **n 顯示暱稱 */
sprintf(buf, "%s", cuser.username);
break;
case 'l': /* **l 顯示上站次數 */
sprintf(buf, "%d", cuser.numlogins);
break;
case 'p': /* **p 顯示發文次數 */
sprintf(buf, "%d", cuser.numposts);
break;
case 'g': /* **g 顯示金幣 */
sprintf(buf, "%d", cuser.gold);
break;
case 'm': /* **m 顯示銀幣 */
sprintf(buf, "%u", cuser.money);
break;
case 't': /* **t 顯示日期 */
sprintf(buf, "%s", Now());
break;
case 'u': /* **u 顯示線上人數 */
sprintf(buf, "%d", total_user);
break;
case 'b': /* **b 顯示站名 */
sprintf(buf, "%s", BBSNAME);
break;
default:
*buf = '\0';
}
if (*buf)
{
outs(buf);
return strlen(buf);
}
else
return 0;
}
void
outx(str)
uschar *str;
{
int ch;
while (ch = *str)
{
/* itoc.020301: ESC + * + s 等控制碼 */
if (ch == KEY_ESC && str[1] == '*')
{
if (out_extend_ansi_char(str[2]))
{
str += 3;
continue;
}
}
outc(ch);
str++;
}
}
char
outax(str, max)
uschar *str;
int max;
{
uschar old_ch, ch;
char *ptr, ret;
char ansi_buf[80]; /* 雙色字緩衝區 */
int len, in_ansi, in_chi, i;
in_chi = in_ansi = len = ret = i = 0;
*ansi_buf = '\0';
ptr = str;
while ((ch = *ptr++))
{
if (in_ansi)
{
if (!(strchr(STR_ANSICODE, ch)))
{
in_ansi = 0;
if (i)
ansi_buf[i++] = ch;
}
}
else
{
if (ch == KEY_ESC)
{
in_ansi = 1;
if (*ptr == '*')
{
in_ansi = out_extend_ansi_char(ptr[1]);
if (in_ansi)
{
len += in_ansi;
ptr += 2;
in_ansi = 0;
continue;
}
}
}
else
{
if (in_chi || IS_ZHC_HI(ch))
{
in_chi ^= 1;
if (in_chi)
old_ch = ch;
else
{
outc(old_ch);
if (i)
{
ansi_buf[i] = '\0';
outs(ansi_buf);
i = 0;
*ansi_buf = '\0';
}
}
}
len++;
}
}
if (in_chi && in_ansi)
ansi_buf[i++] = ch;
else if (!(in_chi))
outc(ch);
if (len >= max)
{
if (in_ansi || (*ptr == KEY_ESC))
continue;
/* 解決 '>' 誤判問題, 及 ANSI Code */
if (*(ptr + 1) == '\0' || *(ptr + 1) == KEY_ESC)
continue;
ret++;
if (in_chi)
ret++;
break;
}
}
return ret;
}
char
outa(str, max, end)
uschar *str;
int max;
int end;
{
uschar old_ch, ch;
char *ptr, ret;
int len, in_ansi, in_chi;
in_chi = in_ansi = len = ret = 0;
ptr = str;
while ((ch = *ptr++))
{
if (in_chi || IS_ZHC_HI(ch))
in_chi ^= 1;
if (in_ansi)
{
if (!(strchr(STR_ANSICODE, ch)))
in_ansi = 0;
}
else
{
if (ch == KEY_ESC)
in_ansi = 1;
else if (++len >= max)
break;
}
}
if (ch)
{
old_ch = *ptr;
*ptr = '\0';
}
max = (in_chi) ? max - 1 : max;
prints("%-*.*s", max, max, str);
if (ch)
*ptr = old_ch;
if (in_chi)
{
outc(' ');
ret++;
}
if (end)
outs(str_ransi);
return ret;
}
------------------------------------------------------------------------------
:src/maple/more.c
+ typedef struct MORELINE
+ {
+ char data[ANSILINELEN];
+ char auto_break_flag; /* 0: 無換行, 1: 有換行 */
+ int more_offset; /* 畫面偏移值 */
+ int b_cols; /* bottom columns length */
+ #ifdef SLIDE_SHOW
+ int slideshow; /* !=0: 撥放 movie 的速度 */
+ #endif
+ off_t header_offset; /* Header 區域 */
+ } MORELINE;
static uschar *fimage; /* file image begin */
static uschar *fend; /* file image end */
static uschar *foff; /* 目前讀到哪裡 */
+ static uschar *flast; /* last page start offset address*/
------------------------------------------------------------------------------
:src/maple/more.c - more_slideshow()
/* 因應本次更新修正 */
static int
more_slideshow(moreline)
MORELINE *moreline;
{
int ch;
if (moreline->slideshow == 0)
{
ch = vkey();
if (ch == '@')
{
moreline->slideshow =
vans("請選擇放映的速度 1(最慢)~9(最快)?撥放中按任意鍵可停止撥放:")
- '0';
if (moreline->slideshow < 1 || moreline->slideshow > 9)
moreline->slideshow = 5;
ch = KEY_PGDN;
}
}
else
{
struct timeval tv[9] =
{
{4, 0}, {3, 0}, {2, 0}, {1, 500000}, {1, 0},
{0, 800000}, {0, 600000}, {0, 400000}, {0, 200000}
};
refresh();
ch = 1;
if (select(1, (fd_set *) &ch, NULL, NULL,
tv + moreline->slideshow - 1) > 0)
{
/* 若撥放中按任意鍵,則停止撥放 */
moreline->slideshow = 0;
ch = vkey();
}
else
{
ch = KEY_PGDN;
}
}
return ch;
}
------------------------------------------------------------------------------
:src/maple/more.c - more_line()
/*
mode = 0 : 一般模式
mode = 1 : Get Offset
*/
static int
more_line(moreline, fsrc, mode)
MORELINE *moreline;
uschar *fsrc;
char mode;
{
int len, bytes, in_ansi, in_chi;
uschar ch, *offset;
char *buf, no_auto_break;
len = bytes = in_ansi = in_chi = moreline->auto_break_flag = 0;
offset = fsrc;
if (offset <= fimage + moreline->header_offset)
no_auto_break = 1;
else
no_auto_break = moreline->more_offset;
if (mode == 0)
buf = moreline->data;
for (;;)
{
if (offset >= fend)
break;
ch = *offset;
offset++;
bytes++;
if (ch == '\n')
break;
if (in_ansi)
{
if (!(strchr(STR_ANSICODE, ch)))
in_ansi = 0;
}
else
{
if (ch == KEY_ESC)
in_ansi = 1;
else
{
if (isprint2(ch))
{
if (in_chi || IS_ZHC_HI(ch))
in_chi ^= 1;
}
else
ch = ' '; /* 印出不來的都換成空白 */
len++;
}
}
if (mode == 0)
*buf++ = ch;
/* 若不含控制碼的長度已達 b_cols 字,或含控制碼的長度已達 ANSILINELEN-1
,那麼離開迴圈 */
if ((bytes >= ANSILINELEN - 1) ||
(no_auto_break == 0 && (len >= moreline->b_cols)))
{
/* itoc.031123: 如果是控制碼,即使不含控制碼的長度已達 b_cols 了
,還可以繼續吃 */
if ((in_ansi || (offset < fend && *offset == KEY_ESC)) &&
bytes < ANSILINELEN - 1)
continue;
/* itoc.031123: 再檢查下一個字是不是 '\n',避免恰好是 b_cols 或
ANSILINELEN-1 時,會多跳一行空白行 */
if (offset < fend && *offset == '\n')
{
offset++;
bytes++;
}
/* 因應 PTT 80 行顯示 (moreline->b_cols 為 79, 可刪除此判斷) */
else if (offset < fend && (*(offset + 1) == '\n' || *(offset + 1) == KEY_ESC))
continue;
else
{
if (in_chi)
{
offset--;
bytes--;
buf--;
}
if (no_auto_break == 0)
{
moreline->auto_break_flag++;
if (in_chi)
moreline->auto_break_flag++;
}
}
break;
}
}
if (mode == 0)
{
*buf = '\0';
foff = offset;
}
return bytes;
}
------------------------------------------------------------------------------
:src/maple/more.c - outs_line()
/* 修改幅度大, 請整個函式換掉 */
static int
outs_line(moreline) /* 印出一般內容 */
MORELINE *moreline;
{
int ch1, ch2, ch3, ansi, curr_offset, in_ansi, in_chi;
char *str, *ptr, last_ansi_code[40], num_ch_space;
char buf[ANSILINELEN];
off_t ret;
/* ※處理引用者 & 引言 */
ptr = str = moreline->data;
ch1 = str[0];
ch2 = str[1];
ch3 = str[2];
last_ansi_code[0] = '\0';
if ((ch1 == '\241' && ch2 == '\260') || /* ※ ==> 引言者 */
(ch1 == QUOTE_CHAR3 && ch2 == QUOTE_CHAR3 && ch3 == QUOTE_CHAR1))
{
ansi = 1;
strcpy(last_ansi_code, COLOR_MORE_QUOTE);
outs(last_ansi_code);
}
/* 引言 */
else if ((ch2 == ' ') && (ch1 == QUOTE_CHAR1 || ch1 == QUOTE_CHAR2))
{
ansi = 1;
strcpy(last_ansi_code, (ch3 == QUOTE_CHAR1 || ch3 == QUOTE_CHAR2) ?
COLOR_MORE_QUOTE2 : COLOR_MORE_QUOTE3);
outs(last_ansi_code); /* 引用一層/二層不同顏色 */
}
else
ansi = 0;
/* 計算偏移及取得最後 ANSI Code*/
if (moreline->more_offset)
{
curr_offset = in_ansi = in_chi = ch2 = 0;
prints(COLOR_MORE_OFFSET "%c%s%s", QUOTE_CHAR4, str_ransi,
(ansi) ? last_ansi_code : "");
while (ch1 = *ptr)
{
if (ch1 == KEY_ESC)
{
last_ansi_code[ch2++] = ch1;
ansi = in_ansi = 1;
}
else if (in_ansi)
{
if (!strchr(STR_ANSICODE, ch1))
in_ansi = 0;
last_ansi_code[ch2++] = ch1;
last_ansi_code[ch2] = '\0';
if (in_ansi == 0)
{
outs(last_ansi_code);
ch2 = 0;
}
}
else
{
if (moreline->more_offset == curr_offset)
break;
if (in_chi || IS_ZHC_HI(ch1))
in_chi ^= 1;
curr_offset++;
}
ptr++;
}
if (in_chi)
ptr++;
}
ret = ptr - str;
/* 印出內容 */
if (hunt[0])
{
int len;
char *ptr1, *ptr2;
len = strlen(hunt);
ptr2 = buf;
while (1)
{
if (!(ptr1 = (char *) str_sub(ptr, hunt)))
{
strcpy(ptr2, ptr);
break;
}
/* buf 空間不夠 */
if (buf + ANSILINELEN - 1 <= ptr2 + (ptr1 - ptr) + (len + 7))
break;
str_ncpy(ptr2, ptr, ptr1 - ptr + 1);
ptr2 += ptr1 - ptr;
sprintf(ptr2, COLOR_MORE_MASK "%.*s%s", len, ptr1, str_ransi);
ptr2 += len + 7;
ptr = ptr1 + len;
}
ptr = buf;
}
ch1 = moreline->b_cols;
if (moreline->more_offset)
{
if (moreline->more_offset > 1);
ch1--;
if (in_chi)
{
outc(' ');
ch1--;
}
}
#ifdef SHOW_USER_IN_TEXT
num_ch_space = outax(ptr, ch1);
#else
num_ch_space = outa(ptr, ch1, 1);
#endif
if (moreline->auto_break_flag--)
{
if (moreline->auto_break_flag)
outc(' ');
prints(COLOR_MORE_OFFSET "%c", QUOTE_CHAR5);
ansi = 1;
}
else if (moreline->more_offset && num_ch_space--)
{
if (num_ch_space)
outc(' ');
prints(COLOR_MORE_OFFSET "%c", QUOTE_CHAR1);
ansi = 1;
}
if (ansi)
outs(str_ransi);
return ret;
}
------------------------------------------------------------------------------
:src/maple/more.c - outs_header()
/* 修改幅度大, 請整個函式換掉 */
static char header1[LINE_HEADER][LEN_AUTHOR1] = STR_HEADER;
static char header2[LINE_HEADER][LEN_AUTHOR2] = STR_HEADER2;
static void
outs_header(moreline, header_len) /* 印出檔頭 */
MORELINE *moreline;
int header_len;
{
int i;
char *buf, *ptr, *word;
buf = moreline->data;
/* 處理檔頭 */
for (i = 0; i < LINE_HEADER; i++)
{
if ((header_len == LEN_AUTHOR1 &&
!memcmp(buf, header1[i], LEN_AUTHOR1 - 1)) ||
(header_len == LEN_AUTHOR2 &&
!memcmp(buf, header2[i], LEN_AUTHOR2 - 1)))
{
word = buf + header_len;
/* 作者/看板 檔頭有二欄,特別處理 */
if (i == 0 &&
((ptr = strstr(word, str_post1)) || (ptr = strstr(word, str_post2))))
{
if (ptr > word)
ptr[-1] = '\0';
ptr[4] = '\0';
prints(COLOR5 " %s " COLOR6 "%-*.*s" COLOR5 " %s " COLOR6
"%-13s\033[m", header1[0], d_cols + 53, d_cols + 53, word
, ptr, ptr + 5, str_ransi);
}
else
{
/* 其他檔頭都只有一欄 */
prints(COLOR5 " %s " COLOR6 "%-*.*s\033[m",
header1[i], d_cols + 72, d_cols + 72, word, str_ransi);
}
return;
}
}
/* 如果不是檔頭,就當一般文字印出 */
outs_line(buf);
}
------------------------------------------------------------------------------
:src/maple/more.c - outs_footer()
/* 修改幅度大, 請整個函式換掉 */
static void
outs_footer(moreline, lino, fsize)
MORELINE *moreline;
int lino;
int fsize;
{
int i, j;
j = moreline->b_cols + moreline->more_offset;
sprintf(moreline->data, FOOTER_MORE, (lino - 2) / PAGE_SCROLL + 1,
((foff - fimage) * 100) / fsize, 0, "", (lino > PAGE_SCROLL) ?
lino - PAGE_SCROLL : 1, lino, moreline->more_offset + 1, j);
i = b_cols + strlen(COLOR1) + (strlen(COLOR2) * 3) + (strlen(FCOLOR) * 3)
- strlen(moreline->data) - 1;
sprintf(moreline->data, FOOTER_MORE, (lino - 2) / PAGE_SCROLL + 1,
((foff - fimage) * 100) / fsize, i, "", (lino > PAGE_SCROLL) ?
lino - PAGE_SCROLL : 1, lino, moreline->more_offset + 1, j);
outz(moreline->data);
outs(str_ransi);
}
------------------------------------------------------------------------------
/* 整個函式換掉, 更動幅度大 */
:src/maple/more.c - more()
int
more(fpath, footer)
char *fpath;
char *footer;
{
MORELINE moreline;
FILE *fp;
struct stat st;
char *str;
int i;
int shift; /* 還需要往下移動幾列 */
int lino; /* 目前 line number */
int header_len; /* 檔頭的長度,同時也是站內/站外信的區別 */
int key; /* 按鍵 */
int cmd; /* 中斷時所按的鍵 */
int fsize; /* 檔案大小 */
int hunt_index; /* 搜尋索引 */
int curr_refresh;
/* 每 32 列為一個 block,記錄此 block 的 offset */
static off_t block[MAXBLOCK];
off_t header_end; /* 檔頭結束 */
off_t header_end2; /* 檔頭分隔線 */
if (!(fp = fopen(fpath, "r")))
return -1;
if (fstat(fileno(fp), &st) || !(S_ISREG(st.st_mode)) ||
(fsize = st.st_size) <= 0)
{
fclose(fp);
return -1;
}
lino = strlen(BCOLOR MSG_SEPERATOR "\033[m\n");
if (!(fimage = malloc(fsize + lino)))
return -1;
foff = fimage;
fend = foff + fsize;
memset(&moreline, 0, sizeof(MORELINE));
moreline.b_cols = b_cols - ((currbattr & BRD_NOTRAN) ? 1 : 0);
header_end = header_end2 = hunt_index = curr_refresh = 0;
for (i = 0; ; i++)
{
if (feof(fp) || !(str = fgets(foff, MORE_BUFSIZE, fp)))
break;
shift = strlen(str);
foff += shift;
/* 讀出檔案第一列,來判斷站內信還是站外信 */
if (i == 0)
{
header_len =
!memcmp(str, str_author1, LEN_AUTHOR1) ? LEN_AUTHOR1 :
/* 「作者:」表站內文章 */
!memcmp(str, str_author2, LEN_AUTHOR2) ? LEN_AUTHOR2 :
/* 「發信人:」表轉信文章 */
0; /* 沒有檔頭 */
}
if (i >= (header_len - 2))
break;
if ((header_len == LEN_AUTHOR1 &&
!memcmp(str, header1[i], LEN_AUTHOR1 - 1)) ||
(header_len == LEN_AUTHOR2 &&
!memcmp(str, header2[i], LEN_AUTHOR2 - 1)))
header_end = moreline.header_offset = foff - fimage;
else
{
if (i < (header_len - 2))
break;
}
}
if (header_len)
{
foff -= shift;
memcpy(foff + lino, foff, shift);
memcpy(foff, BCOLOR MSG_SEPERATOR "\033[m\n", lino);
foff += lino + shift;
fsize += lino;
fend = fimage + fsize;
header_end2 = moreline.header_offset = header_end + lino;
}
while ((foff < fend) && (feof(fp) == 0))
foff += fread(foff, MORE_BUFSIZE, MORE_BUFSIZE, fp);
fclose(fp);
/* 歸零 */
flast = foff = fimage;
lino = key = cmd = 0;
memset(&block, 0, sizeof(off_t) * MAXBLOCK);
if (hunt[0]) /* 在 xxxx_browse() 請求搜尋字串 */
{
str_lowest(hunt, hunt);
shift = HUNT_MASK | HUNT_START;
}
else
shift = b_lines;
clear();
for(;;)
{
if (more_line(&moreline, foff, 0))
{
/* ------------------------------------------------- */
/* 印出一列的文字 */
/* ------------------------------------------------- */
/* 首頁前幾列才需要處理檔頭 */
if (foff <= fimage + header_end)
outs_header(&moreline, header_len);
else
{
if (foff <= fimage + header_end2)
#ifdef SHOW_USER_IN_TEXT
outax(moreline.data, moreline.b_cols);
#else
outa(ptr, moreline.b_cols, 1);
#endif
else
hunt_index = outs_line(&moreline);
}
outc('\n');
/* ------------------------------------------------- */
/* 依 shift 來決定動作 */
/* ------------------------------------------------- */
/* itoc.030303.註解: shift 在此的意義
>0: 還需要往下移幾行
<0: 還需要往上移幾行
=0: 結束這頁,等待使用者按鍵 */
if (curr_refresh)
shift--;
else if (shift > 0) /* 還要下移 shift 列 */
{
/* 只有在剛進 more,第一次印第一頁時才可能 lino <= b_lines */
if (lino >= b_lines)
scroll();
lino++;
if ((lino % 32 == 0) && ((i = lino >> 5) < MAXBLOCK))
block[i] = foff - fimage;
if (shift & END_MASK) /* 按 End 鍵 */
{
if (!(shift & END_MORE_MASK))
flast += more_line(&moreline, flast, 1);
}
else if (shift & HUNT_MASK) /* 字串搜尋 */
{
if (shift & HUNT_NEXT) /* 按 n 搜尋下一筆 */
{
flast += more_line(&moreline, flast, 1);
/* 一找到就停於該列 */
if (str_sub(&moreline.data[hunt_index], hunt))
shift = 0;
}
else /* 按 / 開始搜尋 */
{
/* 若在第二頁以後找到,一找到就停於該列;
若在第一頁找到,必須等到讀完第一頁才能停止 */
if (shift & HUNT_START)
{
if (lino > b_lines)
flast += more_line(&moreline, flast, 1);
/* 拿掉 HUNT_START 並加上 HUNT_FOUND */
if (str_sub(&moreline.data[hunt_index], hunt))
shift ^= HUNT_START | HUNT_FOUND;
}
if (shift & HUNT_FOUND && lino >= b_lines)
shift = 0;
}
hunt_index = 0;
}
else
{
if (lino > b_lines)
flast += more_line(&moreline, flast, 1);
shift--;
}
}
else if (shift < 0) /* 還要上移 -shift 列 */
{
shift++;
if (!(shift))
{
move(b_lines, 0);
clrtoeol();
/* 剩下 b_lines+shift 列是 rscroll,offsect 去正確位置;
這裡的 i 是總共要 shift 的列數 */
for (i += b_lines; i > 0; i--)
more_line(&moreline, foff, 0);
}
}
}
if (foff >= fend) /* 已經讀完全部的檔案 */
{
/* 倘若是按 End 移到最後一頁,那麼停留在 100% 而不結束;否則一律結束 */
//if (!(shift & END_MASK))
// break;
if (!(footer))
break;
shift = 0;
}
if (shift) /* 還需要繼續讀資料 */
continue;
if (curr_refresh)
curr_refresh = 0;
/* ------------------------------------------------- */
/* 到此印完所需的 shift 列,接下來印出 footer 並等待 */
/* 使用者按鍵 */
/* ------------------------------------------------- */
re_key:
outs_footer(&moreline, lino, fsize);
#ifdef SLIDE_SHOW
key = more_slideshow(&moreline);
#else
key = vkey();
#endif
if (key == ' ' || key == KEY_PGDN || key == KEY_RIGHT || key == Ctrl('F'))
{
if (foff >= fend)
{
cmd = 'j';
break;
}
shift = PAGE_SCROLL;
}
else if (key == KEY_DOWN || key == '\n')
{
if (foff >= fend)
{
cmd = 'j';
break;
}
shift = 1;
}
else if (key == KEY_PGUP || key == Ctrl('B') || key == KEY_DEL)
{
/* itoc.010324: 到了最開始再上捲表示離開,
並回傳 'k' (keymap[] 定義上一篇) */
if (lino <= b_lines)
{
cmd = 'k';
break;
}
/* 最多只能上捲到一開始 */
i = PAGE_SCROLL + 1 - lino;
shift = BMAX(-PAGE_SCROLL, i);
}
else if (key == KEY_UP)
{
/* itoc.010324: 到了最開始再上捲表示離開,
並回傳 'k' (keymap[] 定義上一篇) */
if (lino <= b_lines)
{
cmd = 'k';
break;
}
shift = -1;
}
else if (key == KEY_END || key == '$')
{
shift = END_MASK;
}
else if (key == KEY_HOME || key == '0')
{
if (lino <= b_lines) /* 已經在最開始了 */
shift = 0;
else
shift = -b_lines;
}
else if (key == '/' || key == 'n')
{
/* 如果按 n 卻未輸入過搜尋字串,那麼視同按 / */
if (key == 'n' && hunt[0])
{
shift = HUNT_MASK | HUNT_NEXT;
}
else
{
if (vget(b_lines, 0, "搜尋(關鍵字):", hunt, sizeof(hunt), DOECHO))
{
str_lowest(hunt, hunt);
shift = HUNT_MASK | HUNT_START;
}
else /* 取消搜尋 */
{
hunt[0] = '\0';
foff = flast;
curr_refresh = 1;
shift = b_lines;
clear();
continue;
}
}
}
else if (key == 'C') /* Thor.980405: more 時可存入暫存檔 */
{
FILE *fp;
if (fp = tbf_open())
{
f_suck(fp, fpath);
fclose(fp);
}
shift = 0; /* 重繪 footer */
}
else if (key == KEY_TAB)
{
moreline.more_offset += TAB_STOP;
if (moreline.more_offset >= ANSILINELEN)
moreline.more_offset = ANSILINELEN;;
foff = flast;
curr_refresh = 1;
shift = b_lines;
clear();
continue;
}
else if (key == KEY_STAB || key == 'z')
{
moreline.more_offset -= TAB_STOP;
if (moreline.more_offset < 0)
moreline.more_offset = 0;
foff = flast;
curr_refresh = 1;
shift = b_lines;
clear();
continue;
}
else if (key == '>' || key == '.')
{
if (moreline.more_offset)
moreline.more_offset++;
else
moreline.more_offset += 2;
if (moreline.more_offset >= MORE_BUFSIZE)
moreline.more_offset = MORE_BUFSIZE;
foff = flast;
curr_refresh = 1;
shift = b_lines;
clear();
continue;
}
else if (key == '<' || key == ',')
{
if (moreline.more_offset)
{
moreline.more_offset--;
foff = flast;
curr_refresh = 1;
shift = b_lines;
clear();
continue;
}
}
else if (key == 'h')
{
screenline slt[T_LINES];
uschar *tmp_fimage;
uschar *tmp_foff, *tmp_flast;
uschar *tmp_fend;
off_t tmp_block[MAXBLOCK];
int tmp_more_offset;
tmp_fimage = fimage;
tmp_foff = foff;
tmp_flast = flast;
tmp_fend = fend;
memcpy(tmp_block, block, sizeof(off_t) * MAXBLOCK);
tmp_more_offset = moreline.more_offset;
vs_save(slt);
xo_help("post");
vs_restore(slt);
moreline.more_offset = tmp_more_offset;
memcpy(block, tmp_block, sizeof(off_t) * MAXBLOCK);
fend = tmp_fend;
flast = tmp_flast;
foff = tmp_foff;
fimage = tmp_fimage;
shift = 0;
}
else /* 其他鍵都是使用者中斷 */
{
/* itoc.041006: 使用者中斷的按鍵要 > 0 (而 KEY_LEFT 是 < 0) */
cmd = (key > 0) ? key : 'q';
break;
}
/* ------------------------------------------------- */
/* 使用者已按鍵,若 break 則離開迴圈;否則依照 shift */
/* 的種類 (亦即按鍵的種類) 而做不同的動作 */
/* ------------------------------------------------- */
if (shift > 0) /* 準備下移 shift 列 */
{
if (shift < (HUNT_MASK | HUNT_START)) /* 一般下移 */
{
/* itoc.041114.註解:
目標是秀出 lino-b_lines+1+shift ~ lino+shift 列的內容:
就只要清 footer 即可,其他的就交給前面循序印 shift 列的程式 */
move(b_lines, 0);
clrtoeol();
/* itoc.041116:
End 的作法其實和一般下移可以是完全一樣的,但是如果遇到超長文章時,
會造成前面循序印 shift 列的程式就得一直翻,直到找到最後一頁,這樣
會做太多 outs_line() 白工,
所以在此特別檢查超長文章時,就先去找最後一頁所在 */
/* 還有一堆沒讀過,才特別處理 */
if ((shift & END_MASK) && (fsize - (foff - fimage) >= MORE_BUFSIZE))
{
int totallino = lino;
/* 先讀到最後一列看看全部有幾列 */
while (more_line(&moreline, foff, 0))
{
totallino++;
if ((totallino % 32 == 0) && ((i = totallino >> 5) < MAXBLOCK))
block[i] = foff - fimage;
}
/* 先位移到上一個 block 的尾端 */
i = (totallino - b_lines) >> 5;
if (i >= MAXBLOCK)
i = MAXBLOCK - 1;
flast = foff = fimage + block[i];
i = i << 5;
/* 再從上一個 block 的尾端位移到 totallino-b_lines+1 列 */
for (i = totallino - b_lines - i; i > 0; i--)
more_line(&moreline, foff, 0);
flast = foff;
lino = totallino - b_lines;
shift |= END_MORE_MASK;
}
}
else
{
/* '/' 從頭開始搜尋 */
lino = 0;
flast = foff = fimage;
clear();
}
}
else if (shift < 0) /* 準備上移 -shift 列 */
{
if (shift > -b_lines) /* 上捲數列 */
{
lino += shift;
/* itoc.041114.註解: 目標是秀出 lino-b_lines+1 ~ lino 列的內容:
1. 先從頭位移到 lino-b_lines+1 列
2. 其中有 b_lines+shift 列是不變的內容,用 rscroll 達成
3. 在前面的 outs_line() 的地方印出 -shift 列
4. 最後再位移剛才 rscroll 的列數
*/
/* 先位移到上一個 block 的尾端 */
i = (lino - b_lines) >> 5;
if (i >= MAXBLOCK)
i = MAXBLOCK - 1;
foff = fimage + block[i];
i = i << 5;
/* 再從上一個 block 的尾端位移到 lino-b_lines+1 列 */
for (i = lino - b_lines - i; i > 0; i--)
more_line(&moreline, foff, 0);
for (i = shift; i < 0; i++)
{
rscroll();
move(0, 0);
clrtoeol();
}
i = shift;
flast = foff;
}
else /* Home */
{
/* itoc.041226.註解: 目標是秀出 1 ~ b_lines 列的內容:
作法就是全部都歸零,從頭再印 b_lines 列即可 */
clear();
flast = foff = fimage;
lino = 0;
shift = b_lines;
}
}
else /* 重繪 footer 並 re-key */
{
move(b_lines, 0);
clrtoeol();
goto re_key;
}
} /* 迴圈的結束 */
/* --------------------------------------------------- */
/* 檔案已經秀完 (cmd = 0) 或 使用者中斷 (cmd != 0) */
/* --------------------------------------------------- */
free(fimage);
if (!cmd) /* 檔案正常秀完,要處理 footer */
{
if (footer) /* 有 footer */
{
if (footer != (char *) -1)
outf(footer);
else
outs(str_ransi);
}
else /* 沒有 footer 要 vmsg() */
{
/* lkchu.981201: 先清一次以免重疊顯示 */
move(b_lines, 0);
clrtoeol();
if (vmsg(NULL) == 'C') /* Thor.990204: 特別注意若回傳 'C' 表示暫存檔 */
{
FILE *fp;
if (fp = tbf_open())
{
f_suck(fp, fpath);
fclose(fp);
}
}
}
}
else /* 使用者中斷,直接離開 */
outs(str_ransi);
hunt[0] = '\0';
/* Thor.990204: 讓key可回傳至more外 */
return cmd;
}
------------------------------------------------------------------------------
--
=[﹎:�摃�◣��:﹎ Origin ]|[ ���O���� cpu.tfcis.org ]|[�搟說�﹎:]=
=[﹊:�摃�╱��:﹊ Author ]|[ cszone.twbbs.org ]|[���插�﹊:]=