From b075088def7f0a5541444d0a38473071290af77a Mon Sep 17 00:00:00 2001 From: Akira Date: Sat, 19 Oct 2013 02:57:40 +0900 Subject: [PATCH] Add regex search on the thread title view and the res view Add refresh command(r) on the thread title view and the res view Fix cookie bug that caused message write fail. --- Makefile | 4 +- README | 21 ++- help.txt | 21 ++- src/_2ch/maru_2ch.c | 5 +- src/env.c | 2 +- src/inc/env.h | 1 + src/inc/error.h | 2 + src/inc/nt_string.h | 2 + src/inc/ui/disp.h | 1 + src/inc/ui/disp_win.h | 1 + src/inc/utils/db.h | 2 +- src/main.c | 42 ++++- src/net/nt_cookie.c | 72 ++++++--- src/net/nt_http.c | 3 +- src/net/nt_http_response_header.c | 3 + src/ui/disp_reslist.c | 314 +++++++++++++++++++++++++++++++++++++- src/ui/disp_string.c | 11 +- src/ui/disp_threadlist.c | 161 ++++++++++++++++++- src/ui/disp_win.c | 1 + src/utils/nt_std_t.c | 10 -- 20 files changed, 617 insertions(+), 62 deletions(-) diff --git a/Makefile b/Makefile index 88a337a..b860693 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,9 @@ #GDBM_COMPT_OPT = -DGDBM_COMPT #Option for development -CFLAGS = -g -Wall -DDEBUG ${CDEF} ${GDBM_COMPT_OPT} +#CFLAGS = -g -Wall -DDEBUG ${CDEF} ${GDBM_COMPT_OPT} #Option for release -#CFLAGS = -Wall ${CDEF} ${GDBM_COMPT_OPT} +CFLAGS = -Wall ${CDEF} ${GDBM_COMPT_OPT} CDEF = -D_REENTRANT -D_XOPEN_SOURCE_EXTENDED #-D_XOPEN_SOURCE diff --git a/README b/README index b5e59f7..7a56d00 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -ntch version 1.0.1.1 +ntch version 1.0.1.2 Linux用 2ch専用ブラウザー @@ -35,13 +35,20 @@ Linux用 2ch専用ブラウザー l 右カラムへ移動 スレタイ一覧 - :[数字] 指定されたスレッド番号にカーソル移動 + :[数字] 指定されたスレッド番号にカーソル移動 g 最後の行に移動する h [数字]で指定する前の表示位置に戻るUNDO l hで戻った移動を元に戻すREDO + r 板を更新する + /[検索文字列] 指定文字列の後方検索 + ?[検索文字列] 指定文字列の前方検索 + 検索文字列は任意で有り、指定しなかった場合 + 以前に指定した文字列で検索します + デフォルトでregex関数に渡されるので + 標準関数の正規表現が使用できます レス一覧 - :[数字] 指定されたレス番号にカーソル移動 + :[数字] 指定されたレス番号にカーソル移動 g 最後の行に移動する h [数字]で指定する前の表示位置に戻るUNDO l hで戻った移動を元に戻すREDO @@ -62,4 +69,12 @@ Linux用 2ch専用ブラウザー  作成して、以下の書式でIDとパスワードを指定して下さい。 maru-id=[2chビューアーのユーザーID] maru-pw=[2chビューアーのパスワード] + r スレッドを更新する + /[検索文字列] 指定文字列の後方検索 + ?[検索文字列] 指定文字列の前方検索 + 検索文字列は任意で有り、指定しなかった場合 + 以前に指定した文字列で検索します + デフォルトでregex関数に渡されるので + 標準関数の正規表現が使用できます + diff --git a/help.txt b/help.txt index b5e59f7..7a56d00 100644 --- a/help.txt +++ b/help.txt @@ -1,5 +1,5 @@ -ntch version 1.0.1.1 +ntch version 1.0.1.2 Linux用 2ch専用ブラウザー @@ -35,13 +35,20 @@ Linux用 2ch専用ブラウザー l 右カラムへ移動 スレタイ一覧 - :[数字] 指定されたスレッド番号にカーソル移動 + :[数字] 指定されたスレッド番号にカーソル移動 g 最後の行に移動する h [数字]で指定する前の表示位置に戻るUNDO l hで戻った移動を元に戻すREDO + r 板を更新する + /[検索文字列] 指定文字列の後方検索 + ?[検索文字列] 指定文字列の前方検索 + 検索文字列は任意で有り、指定しなかった場合 + 以前に指定した文字列で検索します + デフォルトでregex関数に渡されるので + 標準関数の正規表現が使用できます レス一覧 - :[数字] 指定されたレス番号にカーソル移動 + :[数字] 指定されたレス番号にカーソル移動 g 最後の行に移動する h [数字]で指定する前の表示位置に戻るUNDO l hで戻った移動を元に戻すREDO @@ -62,4 +69,12 @@ Linux用 2ch専用ブラウザー  作成して、以下の書式でIDとパスワードを指定して下さい。 maru-id=[2chビューアーのユーザーID] maru-pw=[2chビューアーのパスワード] + r スレッドを更新する + /[検索文字列] 指定文字列の後方検索 + ?[検索文字列] 指定文字列の前方検索 + 検索文字列は任意で有り、指定しなかった場合 + 以前に指定した文字列で検索します + デフォルトでregex関数に渡されるので + 標準関数の正規表現が使用できます + diff --git a/src/_2ch/maru_2ch.c b/src/_2ch/maru_2ch.c index 48b1088..845ad37 100644 --- a/src/_2ch/maru_2ch.c +++ b/src/_2ch/maru_2ch.c @@ -29,7 +29,7 @@ BOOL get_session_id(nt_maru_2ch_tp marup) { char *url = "https://2chv.tora3.net/futen.cgi"; char post_data[256]; - char out_buf[1024*2]; + char out_buf[1024*4]; char *referer = "https://2chv.tora3.net/"; char *user_agent = "DOLIB/1.00"; nt_link_tp linkp; @@ -55,6 +55,7 @@ BOOL get_session_id(nt_maru_2ch_tp marup) sprintf(post_data, "ID=%s&PW=%s", marup->id, marup->pw); + memset(out_buf, 0, sizeof(out_buf)); if(!nt_http_post(url, post_data, out_buf, sizeof(out_buf), referer, user_agent, linkp, NULL)){ @@ -64,9 +65,9 @@ BOOL get_session_id(nt_maru_2ch_tp marup) if(cptr){ cptr += strlen("SESSION-ID="); marup->sid = nt_trim(cptr); + result = TRUE; } - result = TRUE; ERROR_TRAP: free(kvp); free(linkp); diff --git a/src/env.c b/src/env.c index 66382d0..cb59541 100644 --- a/src/env.c +++ b/src/env.c @@ -21,7 +21,7 @@ char USR_COOKIE_PATH[1024]; char EDITOR_CMD[1024]; int FORCE_REFRESH = 0; static char *app_name = "ntch"; -static char *version_name = "1.0.1.1"; +static char *version_name = "1.0.1.2"; static char *def_editor_cmd = "vi"; char *MARU_ID; diff --git a/src/inc/env.h b/src/inc/env.h index 9001bcb..5b096c8 100644 --- a/src/inc/env.h +++ b/src/inc/env.h @@ -23,6 +23,7 @@ extern char *MARU_PW; #define NT_KEY_ADD 'a' #define NT_KEY_DEL 'd' #define NT_KEY_BOTTOM 'g' +#define NT_KEY_REFRESH 'r' #define NT_KEY_COMMAND1 ':' #define NT_KEY_COMMAND2 '/' #define NT_KEY_COMMAND3 '?' diff --git a/src/inc/error.h b/src/inc/error.h index eb69bf3..a8ce5e9 100644 --- a/src/inc/error.h +++ b/src/inc/error.h @@ -4,5 +4,7 @@ #define NT_ERR_MSG_COUDLNOT_READ_BOARD (L"板情報が読み込めませんでした") #define NT_ERR_MSG_WRITE_MSG_LENGTH (L"メッセージが指定されていません") #define NT_ERR_MSG_WRITE_MSG_ABORTED (L"中止しました") +#define NT_ERR_MSG_REFRESH_THREAD_FAILED (L"スレッドの更新に失敗しました") +#define NT_ERR_MSG_SEARCH_NOT_FOUND (L"文字列が見つかりませんでした") #endif /*_ERROR_H_*/ diff --git a/src/inc/nt_string.h b/src/inc/nt_string.h index d33ac8c..232fb64 100644 --- a/src/inc/nt_string.h +++ b/src/inc/nt_string.h @@ -5,6 +5,8 @@ #define NT_TEXT_DEF_MAIL "sage" #define NT_INFO_WRITE_MSG_SUCCESS (L"メッセージを書き込みました") +#define NT_INFO_REFRESH_THREAD_SUCCESS (L"スレッドを更新しました") +#define NT_INFO_REFRESH_BOARD_SUCCESS (L"板を更新しました") #endif /* _NT_STRING_H */ diff --git a/src/inc/ui/disp.h b/src/inc/ui/disp.h index 612edb0..450604f 100644 --- a/src/inc/ui/disp.h +++ b/src/inc/ui/disp.h @@ -8,6 +8,7 @@ #define DISP_STATE_RESLIST 3 #define DISP_STATE_EDITOR 4 #define DISP_STATE_HTML_RESULT 5 +#define DISP_STATE_REFRESH 6 extern int disp_board_menu(nt_window_tp wp, diff --git a/src/inc/ui/disp_win.h b/src/inc/ui/disp_win.h index d5dbcd9..2d5dfdc 100644 --- a/src/inc/ui/disp_win.h +++ b/src/inc/ui/disp_win.h @@ -11,6 +11,7 @@ typedef struct tag_nt_window_t{ int key; void *data; const char *cmd_param; + wchar_t *status_msg; } nt_window_t; diff --git a/src/inc/utils/db.h b/src/inc/utils/db.h index 9df48f3..37fd776 100644 --- a/src/inc/utils/db.h +++ b/src/inc/utils/db.h @@ -16,7 +16,7 @@ typedef struct tag_nt_db_log_rec_t *nt_db_log_rec_tp; typedef struct tag_nt_db_log_rec_t{ int content_length; - char last_modified[64]; + char last_modified[128]; } nt_db_log_rec_t; typedef struct tag_nt_db_idx_rec_t *nt_db_idx_rec_tp; diff --git a/src/main.c b/src/main.c index cd0da69..8e9a0c8 100644 --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,7 @@ #include "env.h" #include "error.h" +#include "nt_string.h" #include "utils/nt_std_t.h" #include "net/nt_http.h" #include "net/nt_socket.h" @@ -144,6 +145,7 @@ static BOOL DoLoop(WINDOW *scrp) case DISP_STATE_THREADTITLE: werase(twinp->wp); twinp->key = ch; + twinp->status_msg = NULL; title = app_2ch_modelp->selected_boardp->name; draw_title(scrp, title, WA_REVERSE); if(!nt_disp_win_move(scrp, twinp, LINES-1, COLS, 1, 0)) @@ -156,6 +158,18 @@ static BOOL DoLoop(WINDOW *scrp) disp_state = state; ch = NT_KEY_NONE; continue; + }else if(DISP_STATE_REFRESH == state){ + if(nt_read_board(app_2ch_modelp)){ + if(twinp->data){ + free_threadlist_ctx(twinp->data); + twinp->data = NULL; + } + ch = NT_KEY_NONE; + status_msg = NT_INFO_REFRESH_BOARD_SUCCESS; + continue; + }else{ + status_msg = NT_ERR_MSG_COUDLNOT_READ_BOARD; + } }else if(DISP_STATE_RESLIST == state){ if(!nt_read_thread(app_2ch_modelp)){ wclear(scrp); @@ -169,6 +183,8 @@ static BOOL DoLoop(WINDOW *scrp) disp_state = state; ch = NT_KEY_NONE; continue; + }else{ + status_msg = twinp->status_msg; } } break; @@ -183,15 +199,25 @@ static BOOL DoLoop(WINDOW *scrp) state = disp_reslist(rwinp, app_2ch_modelp); if(DISP_STATE_ERROR == state){ goto END_WHILE; + }else if(state == DISP_STATE_REFRESH){ + ch = NT_KEY_NONE; + if(!nt_read_thread(app_2ch_modelp)){ + status_msg = NT_ERR_MSG_REFRESH_THREAD_FAILED; + wclear(scrp); + continue; + } + if(rwinp->data){ + free_reslist_ctx(rwinp->data); + rwinp->data = NULL; + } + status_msg = NT_INFO_REFRESH_THREAD_SUCCESS; + wclear(scrp); + continue; }else if(state != DISP_STATE_RESLIST){ disp_state = state; ch = NT_KEY_NONE; continue; } - if(status_msg){ - print_error(scrp, status_msg); - status_msg = NULL; - } break; case DISP_STATE_EDITOR: disp_state = DISP_STATE_RESLIST; @@ -244,6 +270,11 @@ static BOOL DoLoop(WINDOW *scrp) goto END_WHILE; }/* end switch*/ + if(status_msg){ + print_error(scrp, status_msg); + status_msg = NULL; + } + move(LINES-1,COLS-1); touchwin(scrp); wrefresh(scrp); @@ -259,6 +290,7 @@ static BOOL DoLoop(WINDOW *scrp) case NT_KEY_ADD: case NT_KEY_DEL: case NT_KEY_BOTTOM: + case NT_KEY_REFRESH: break; case NT_KEY_CLOSE: wclear(scrp); @@ -315,7 +347,7 @@ static int draw_title(WINDOW *wp, wchar_t *title, attr_t attr) -static void print_error(WINDOW *wp,wchar_t *msg) +static void print_error(WINDOW *wp, wchar_t *msg) { move(LINES-1,0); nt_add_wstr(wp, msg, 0); diff --git a/src/net/nt_cookie.c b/src/net/nt_cookie.c index 81a56c6..f73897f 100644 --- a/src/net/nt_cookie.c +++ b/src/net/nt_cookie.c @@ -157,7 +157,8 @@ static char* merge_cookie(const char *val1, const char *val2) { char *cptr; int len1, len2, len; - int i, j, state, idx; + int i, j, state; + int start, end; const char *val; char *key, *value; nt_key_value_tp kvp; @@ -182,22 +183,35 @@ static char* merge_cookie(const char *val1, const char *val2) len = len2; } state = 0; - idx = 0; + start = 0; + end = 0; for(j = 0; j < len; j++){ c = val[j]; switch(c){ case ';': - if(state == 0){ - key = nt_substr(val, idx, j); + if(start >= end){ + state = 0; + start = j + 1; + end = start; + break; + } + if(state == 1){ + key = nt_substr(val, start, end); value = nt_str_clone(" "); + }else if(state == 3){ + value = nt_substr(val, start, end); }else{ - value = nt_substr(val, idx, j); + state = 0; + start = j + 1; + end = start; + break; } if(strstr(key, "expires") || strstr(key, "path")){ free(key); free(value); state = 0; - idx = j+1; + start = j + 1; + end = start; break; } kvp = nt_key_value_alloc(key, value); @@ -210,23 +224,38 @@ static char* merge_cookie(const char *val1, const char *val2) if(!linkp) linkp = wrk_linkp; state = 0; - idx = j+1; + start = j + 1; + end = start; break; case '=': - key = nt_substr(val, idx, j); - state = 1; - idx = j+1; + key = nt_substr(val, start, end); + state = 2; + start = j+1; + end = start; + break; + case ' ': + if(state == 0 || state == 2){ + start = j+1; + }else if(state == 1 || state == 3){ + end = j; + } break; default: + if(state == 0){ + state = 1; + }else if(state == 2){ + state = 3; + } + end = j+1; break; - } - } - if(idx < j){ - if(state == 0){ - key = nt_substr(val, idx, j); + }/* end switch */ + } /* end for */ + if(start < end){ + if(state == 0 || state == 1){ + key = nt_substr(val, start, end); value = nt_str_clone(" "); - }else{ - value = nt_substr(val, idx, j); + }else if(state == 2 || state == 3){ + value = nt_substr(val, start, end); } if(strstr(key, "expires") || strstr(key, "path")){ @@ -235,8 +264,13 @@ static char* merge_cookie(const char *val1, const char *val2) kvp = nt_key_value_alloc(key, value); if(linkp){ wrk_linkp = nt_link_find(linkp, kvp, cmp_link_func); - if(wrk_linkp) - nt_link_remove(linkp, wrk_linkp); + if(wrk_linkp){ + wrk_linkp = nt_link_remove(linkp, wrk_linkp); + if(wrk_linkp){ + kvp_free_func(wrk_linkp->data); + free(wrk_linkp); + } + } } wrk_linkp = nt_link_add_data(linkp, kvp); if(!linkp) diff --git a/src/net/nt_http.c b/src/net/nt_http.c index 70a8ff5..757d006 100644 --- a/src/net/nt_http.c +++ b/src/net/nt_http.c @@ -32,7 +32,7 @@ BOOL nt_http_post(const char *url, const char *post_data, { nt_socket_tp socketp = NULL; int fd = -1, sockfd = 0; - char data[1024*2]; + char data[1024*8]; char ssl_connect[512]; size_t data_len; int nread; @@ -376,6 +376,7 @@ BOOL nt_http_get(const char *url, const char *out_path, break; } }while(nread > 0); + nt_http_save_response_header(out_path, responsep); result = TRUE; break; case 304: /* Not Modified */ diff --git a/src/net/nt_http_response_header.c b/src/net/nt_http_response_header.c index 4e8a8be..655ad65 100644 --- a/src/net/nt_http_response_header.c +++ b/src/net/nt_http_response_header.c @@ -39,6 +39,9 @@ BOOL nt_http_save_response_header(const char *out_path, assert(out_path != NULL); assert(responsep != NULL); + if(!responsep->last_modified) + return TRUE; + if(!nt_db_cpy_key(out_path, key)){ return FALSE; } diff --git a/src/ui/disp_reslist.c b/src/ui/disp_reslist.c index f607dd1..d072c8b 100644 --- a/src/ui/disp_reslist.c +++ b/src/ui/disp_reslist.c @@ -2,8 +2,10 @@ #include #include #include +#include #include #include +#include #include "env.h" #include "utils/nt_std_t.h" @@ -23,12 +25,22 @@ typedef struct tag_ctx_reslist_t int max_cur_offset; nt_stack_tp selected_num_stackp; + regex_t regex; + BOOL regex_init; + int sel_res_no; + int sel_res_line; + } ctx_reslist_t; static ctx_reslist_tp init_context(nt_2ch_model_tp modelp); static void int_ptr_free(void *ptr); static BOOL parse_cmd1(const char *param, int *statep); +static BOOL search_line_asc(regex_t *regexp, nt_link_tp reslistp, + int *sel_res_no, int *sel_res_line, int column); +static BOOL search_line_desc(regex_t *regexp, ctx_reslist_tp ctxp, + nt_link_tp reslistp, + int *sel_res_no, int *sel_res_line, int column); int disp_reslist(nt_window_tp wp, nt_2ch_model_tp modelp) { @@ -47,6 +59,10 @@ int disp_reslist(nt_window_tp wp, nt_2ch_model_tp modelp) wchar_t *cptr; nt_link_tp link_curp; int state; + BOOL search_asc; + BOOL adjust; + BOOL set_value; + int line_num; ctxp = (ctx_reslist_tp)wp->data; if(!ctxp){ @@ -62,7 +78,7 @@ int disp_reslist(nt_window_tp wp, nt_2ch_model_tp modelp) if(ctxp->max_cur_res < 0 || ctxp->max_cur_offset < 0){ wlines = wp->lines; int cur_res = ctxp->res_num - 1; - /* get the bottom res */ + /* get the bottom scroll position*/ clistp = threadp->reslistp->prev; while(clistp != threadp->reslistp){ resp = (nt_res_tp)clistp->data; @@ -122,6 +138,8 @@ int disp_reslist(nt_window_tp wp, nt_2ch_model_tp modelp) } switch(ch){ + case NT_KEY_REFRESH: + return DISP_STATE_REFRESH; case NT_KEY_CLOSE: return DISP_STATE_THREADTITLE; case NT_KEY_BOTTOM: @@ -177,6 +195,107 @@ int disp_reslist(nt_window_tp wp, nt_2ch_model_tp modelp) for(i = 0; i < num; i++) clistp = clistp->next; break; + case NT_KEY_COMMAND2: + case NT_KEY_COMMAND3: + search_asc = (ch == NT_KEY_COMMAND2); + if(wp->cmd_param && wp->cmd_param[0] != '\0'){ + if(0 != regcomp(&(ctxp->regex), + wp->cmd_param, REG_EXTENDED)){ + if(ctxp->regex_init){ + regfree(&(ctxp->regex)); + ctxp->regex_init = FALSE; + break; + } + } + if(!ctxp->regex_init) + ctxp->regex_init = TRUE; + } + if(!ctxp->regex_init) + break; + adjust = FALSE; + if(search_asc){ + if(search_line_asc(&(ctxp->regex),threadp->reslistp, + &ctxp->sel_res_no, &ctxp->sel_res_line, + wp->cols - 5)){ + adjust = TRUE; + } + }else{ + if(search_line_desc(&(ctxp->regex),ctxp, + threadp->reslistp, + &ctxp->sel_res_no, &ctxp->sel_res_line, + wp->cols - 5)){ + adjust = TRUE; + } + } + if(adjust){ + set_value = FALSE; + rows = ctxp->res_num - 1; + wlines = wp->lines / 2; + wlines -= ctxp->sel_res_line; + clistp = threadp->reslistp->prev; + do{ + if(rows <= ctxp->sel_res_no){ + resp = (nt_res_tp)clistp->data; + if(!resp->msg_line_linkp){ + parse_res_msg(resp, wp->cols-5); + } + if(resp->msg_header_line_num <= 0){ + if(-1 == swprintf(buf, sizeof(buf)-1, + L"%5d. %ls %ls %ls", + resp->seq_no, resp->name, + resp->mail, resp->misc)){ + resp->msg_header_line_num = 1; + }else{ + len = wcslen(buf); + cptr = buf; + while(len > 0){ + num = nt_get_wc_count_within_colmns( + cptr, wp->cols); + if(num <= 0) + break; + resp->msg_header_line_num++; + len -= num; + cptr += num; + } + } + } + if(rows == ctxp->sel_res_no){ + if(wlines <= ctxp->sel_res_line){ + ctxp->cur_res = rows; + ctxp->cur_res_offset = + resp->msg_header_line_num + + (ctxp->sel_res_line - wlines); + set_value = TRUE; + break; + } + wlines -= ctxp->sel_res_line; + }else if(wlines <= (resp->msg_line_num+1)){ + ctxp->cur_res = rows; + ctxp->cur_res_offset = + resp->msg_header_line_num + wlines; + set_value = TRUE; + break; + }else{ + wlines -= resp->msg_line_num + 1; + } + if(wlines <= resp->msg_header_line_num){ + ctxp->cur_res = rows; + ctxp->cur_res_offset = + resp->msg_header_line_num - wlines; + set_value = TRUE; + break; + } + wlines -= resp->msg_header_line_num; + } + rows--; + clistp = clistp->prev; + }while(clistp != threadp->reslistp->prev); + if(!set_value){ + ctxp->cur_res = 0; + ctxp->cur_res_offset = 0; + } + } + break; case NT_KEY_COMMAND1: assert(wp->cmd_param); if(parse_cmd1(wp->cmd_param, &state)){ @@ -202,7 +321,6 @@ int disp_reslist(nt_window_tp wp, nt_2ch_model_tp modelp) for(i = 0; i < num; i++) clistp = clistp->next; nt_stack_push(ctxp->selected_num_stackp, nptr); - //bottom_chk = TRUE; break; case NT_KEY_UP: ctxp->cur_res_offset--; @@ -469,17 +587,26 @@ int disp_reslist(nt_window_tp wp, nt_2ch_model_tp modelp) continue; link_curp = resp->msg_line_linkp; + line_num = 0; do{ cptr = (wchar_t*)link_curp->data; if(res_offset >= ctxp->cur_res_offset){ wmove(wp->wp, rows, 5); - nt_add_wstr(wp->wp, cptr, 0); + if(i == ctxp->sel_res_no && + line_num == ctxp->sel_res_line){ + /*fprintf(stderr, "hilighted no: %d, line: %d\n", + i, line_num);*/ + nt_add_wstr(wp->wp, cptr, WA_REVERSE); + }else{ + nt_add_wstr(wp->wp, cptr, 0); + } rows++; if(rows == wp->lines) goto END_FOR; }else{ res_offset++; } + line_num++; link_curp = link_curp->next; }while(resp->msg_line_linkp != link_curp); @@ -518,7 +645,7 @@ static ctx_reslist_tp init_context(nt_2ch_model_tp modelp) { ctx_reslist_tp ctxp; nt_thread_tp threadp; - ctxp = (ctx_reslist_tp)calloc(1,sizeof(nt_2ch_model_t)); + ctxp = (ctx_reslist_tp)calloc(1,sizeof(ctx_reslist_t)); if(!ctxp) return NULL; @@ -531,6 +658,9 @@ static ctx_reslist_tp init_context(nt_2ch_model_tp modelp) ctxp->max_cur_res = -1; ctxp->max_cur_offset = -1; ctxp->selected_num_stackp = nt_stack_alloc(); + ctxp->regex_init = FALSE; + ctxp->sel_res_no = -1; + ctxp->sel_res_line = -1; return ctxp; } @@ -542,6 +672,8 @@ void free_reslist_ctx(void *ptr) return; ctxp = (ctx_reslist_tp)ptr; nt_stack_free(ctxp->selected_num_stackp, &int_ptr_free); + if(ctxp->regex_init) + regfree(&(ctxp->regex)); free(ptr); } @@ -551,3 +683,177 @@ static void int_ptr_free(void *ptr) } +static BOOL search_line_asc(regex_t *regexp, nt_link_tp reslistp, + int *sel_res_no, int *sel_res_line, int column) +{ + nt_link_tp clistp, listp; + nt_res_tp resp; + int cur, line, res_no, res_line; + wchar_t *cptr; + char buf[256]; + size_t nmatch = 5; + regmatch_t pmatch[5]; + + if(!reslistp) + return FALSE; + + if(*sel_res_no < 0) + res_no = 0; + else + res_no = *sel_res_no; + if(*sel_res_line < 0) + res_line = 0; + else + res_line = *sel_res_line + 1; + + cur = 0; + clistp = reslistp; + do{ + if(cur >= res_no){ + resp = (nt_res_tp)clistp->data; + if(!resp->msg_line_linkp) + parse_res_msg(resp, column); + listp = resp->msg_line_linkp; + line = 0; + do{ + if(line >= res_line){ + cptr = (wchar_t*)listp->data; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_res_line = line; + *sel_res_no = cur; + return TRUE; + } + } + } + line++; + listp = listp->next; + }while(listp != resp->msg_line_linkp); + res_line = 0; + } + cur++; + clistp = clistp->next; + }while(clistp != reslistp); + + cur = 0; + clistp = reslistp; + do{ + if(cur >= res_no) + break; + + resp = (nt_res_tp)clistp->data; + if(!resp->msg_line_linkp) + parse_res_msg(resp, column); + listp = resp->msg_line_linkp; + line = 0; + do{ + if(line >= res_line){ + cptr = (wchar_t*)listp->data; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_res_line = line; + *sel_res_no = cur; + return TRUE; + } + } + } + line++; + listp = listp->next; + }while(listp != resp->msg_line_linkp); + res_line = 0; + cur++; + clistp = clistp->next; + }while(clistp != reslistp); + return FALSE; +} + +static BOOL search_line_desc(regex_t *regexp, ctx_reslist_tp ctxp, + nt_link_tp reslistp, + int *sel_res_no, int *sel_res_line, int column) +{ + nt_link_tp clistp, listp; + nt_res_tp resp; + int cur, line, res_no, res_line; + wchar_t *cptr; + char buf[256]; + size_t nmatch = 5; + regmatch_t pmatch[5]; + + if(!reslistp) + return FALSE; + + if(*sel_res_no < 0){ + res_no = ctxp->res_num - 1; + }else{ + res_no = *sel_res_no; + } + if(*sel_res_line < 0){ + res_line = INT_MAX; + }else{ + res_line = *sel_res_line - 1; + } + + cur = ctxp->res_num - 1; + clistp = reslistp->prev; + do{ + if(cur <= res_no){ + resp = (nt_res_tp)clistp->data; + if(!resp->msg_line_linkp) + parse_res_msg(resp, column); + listp = resp->msg_line_linkp->prev; + line = resp->msg_line_num - 1; + do{ + if(line <= res_line){ + cptr = (wchar_t*)listp->data; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_res_line = line; + *sel_res_no = cur; + return TRUE; + } + } + } + line--; + listp = listp->prev; + }while(listp != resp->msg_line_linkp->prev); + res_line = resp->msg_line_num - 1; + } + cur--; + clistp = clistp->prev; + }while(clistp != reslistp->prev); + + cur = ctxp->res_num - 1; + clistp = reslistp->prev; + do{ + if(cur <= res_no) + break; + + resp = (nt_res_tp)clistp->data; + if(!resp->msg_line_linkp) + parse_res_msg(resp, column); + listp = resp->msg_line_linkp->prev; + line = resp->msg_line_num - 1; + do{ + if(line >= res_line){ + cptr = (wchar_t*)listp->data; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_res_line = line; + *sel_res_no = cur; + return TRUE; + } + } + } + line--; + listp = listp->prev; + }while(listp != resp->msg_line_linkp->prev); + res_line = resp->msg_line_num - 1; + cur--; + clistp = clistp->prev; + }while(clistp != reslistp->prev); + return FALSE; +} diff --git a/src/ui/disp_string.c b/src/ui/disp_string.c index da04931..a5831c4 100644 --- a/src/ui/disp_string.c +++ b/src/ui/disp_string.c @@ -76,12 +76,13 @@ int nt_add_wnstr(WINDOW *w, wchar_t *wc, attr_t attr, size_t colmns) c.chars[1] = L'\0'; len = wcslen(wc); for(i = 0; i < len && col < colmns; i++){ - if(wc[i] > 127){ + if(wc[i] <= 128 || + (wc[i] >= 0xff66 && wc[i] <= 0xff9d)){ + col++; + }else{ col += 2; if(col >= colmns) break; - }else{ - col++; } c.chars[0] = wc[i]; if(ERR == wadd_wch(w, &c)) @@ -101,9 +102,9 @@ int nt_get_wc_count_within_colmns(wchar_t *wc, size_t colmns) for(i = 0; i < len; i++){ ch = wc[i]; if(ch <= 128 || (ch >= 0xff66 && ch <= 0xff9d)) - col += 2; - else col++; + else + col += 2; if(col > colmns) return i; } diff --git a/src/ui/disp_threadlist.c b/src/ui/disp_threadlist.c index 447fa54..1514e09 100644 --- a/src/ui/disp_threadlist.c +++ b/src/ui/disp_threadlist.c @@ -3,8 +3,10 @@ #include #include #include +#include #include "env.h" +#include "error.h" #include "utils/nt_std_t.h" #include "_2ch/_2ch.h" #include "_2ch/model_2ch.h" @@ -18,9 +20,17 @@ typedef struct tag_ctx_threadlist_t int cursor_pos; int scroll_pos; + regex_t regex; + BOOL regex_init; + int sel_thread_no; + } ctx_threadlist_t; +static BOOL search_line_asc(regex_t *regexp, + nt_link_tp threadlistp, int *sel_thread_no); +static BOOL search_line_desc(regex_t *regexp, + nt_link_tp threadlistp, int *sel_thread_no); static ctx_threadlist_tp init_context(nt_2ch_model_tp modelp); int disp_threadlist(nt_window_tp wp, nt_2ch_model_tp modelp) @@ -33,6 +43,7 @@ int disp_threadlist(nt_window_tp wp, nt_2ch_model_tp modelp) int btm_cur, num, wlines; wchar_t buf[16]; attr_t attr; + BOOL search_asc; ctxp = (ctx_threadlist_tp)wp->data; if(!ctxp){ @@ -46,6 +57,8 @@ int disp_threadlist(nt_window_tp wp, nt_2ch_model_tp modelp) boardp = modelp->selected_boardp; switch(ch){ + case NT_KEY_REFRESH: + return DISP_STATE_REFRESH; case NT_KEY_CLOSE: return DISP_STATE_BOARDMENU; case NT_KEY_BOTTOM: @@ -60,12 +73,46 @@ int disp_threadlist(nt_window_tp wp, nt_2ch_model_tp modelp) ctxp->scroll_pos = wlines; //ctxp->scroll_pos += wlines%2; break; + case NT_KEY_COMMAND2: + case NT_KEY_COMMAND3: + search_asc = (ch == NT_KEY_COMMAND2); + if(wp->cmd_param && wp->cmd_param[0] != '\0'){ + if(0 != regcomp(&(ctxp->regex), + wp->cmd_param, REG_EXTENDED)){ + if(ctxp->regex_init){ + regfree(&(ctxp->regex)); + ctxp->regex_init = FALSE; + break; + } + } + if(!ctxp->regex_init) + ctxp->regex_init = TRUE; + } + if(!ctxp->regex_init) + break; + if(search_asc){ + if(!search_line_asc(&(ctxp->regex), boardp->threadlistp, + &ctxp->sel_thread_no)){ + wp->status_msg = NT_ERR_MSG_SEARCH_NOT_FOUND; + break; + } + }else{ + if(!search_line_desc(&(ctxp->regex), boardp->threadlistp, + &ctxp->sel_thread_no)){ + wp->status_msg = NT_ERR_MSG_SEARCH_NOT_FOUND; + break; + } + } + num = ctxp->sel_thread_no; + //fall through case NT_KEY_COMMAND1: - assert(wp->cmd_param); - num = atoi(wp->cmd_param); - if(0 == num) - break; - num--; + if(ch == NT_KEY_COMMAND1){ + assert(wp->cmd_param); + num = atoi(wp->cmd_param); + if(0 == num) + break; + num--; + } wlines = ctxp->thread_num - num; if(wlines <= 0) break; @@ -198,7 +245,7 @@ static ctx_threadlist_tp init_context(nt_2ch_model_tp modelp) { ctx_threadlist_tp ctxp; nt_board_tp boardp; - ctxp = (ctx_threadlist_tp)calloc(1,sizeof(nt_2ch_model_t)); + ctxp = (ctx_threadlist_tp)calloc(1,sizeof(ctx_threadlist_t)); if(!ctxp) return NULL; @@ -206,6 +253,9 @@ static ctx_threadlist_tp init_context(nt_2ch_model_tp modelp) boardp = modelp->selected_boardp; ctxp->thread_num = nt_link_num(boardp->threadlistp); + ctxp->regex_init = FALSE; + ctxp->sel_thread_no = -1; + return ctxp; } @@ -219,4 +269,103 @@ void free_threadlist_ctx(void *ptr) } +static BOOL search_line_asc(regex_t *regexp, + nt_link_tp threadlistp, int *sel_thread_no) +{ + wchar_t *cptr; + nt_thread_tp threadp; + nt_link_tp clistp; + size_t nmatch = 5; + regmatch_t pmatch[5]; + char buf[256]; + int cur; + + clistp = threadlistp; + cur = 0; + do{ + if(cur > *sel_thread_no){ + threadp = (nt_thread_tp)clistp->data; + cptr = threadp->name; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_thread_no = cur; + return TRUE; + } + } + } + cur++; + clistp = clistp->next; + }while(clistp != threadlistp); + clistp = threadlistp; + cur = 0; + do{ + if(cur > *sel_thread_no) + break; + + threadp = (nt_thread_tp)clistp->data; + cptr = threadp->name; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_thread_no = cur; + return TRUE; + } + } + cur++; + clistp = clistp->next; + }while(clistp != threadlistp); + return FALSE; +} +static BOOL search_line_desc(regex_t *regexp, + nt_link_tp threadlistp, int *sel_thread_no) +{ + wchar_t *cptr; + nt_thread_tp threadp; + nt_link_tp clistp; + size_t nmatch = 5; + regmatch_t pmatch[5]; + char buf[256]; + int cur; + int num; + + clistp = threadlistp->prev; + num = nt_link_num(threadlistp); + cur = num - 1; + do{ + if(cur < *sel_thread_no){ + threadp = (nt_thread_tp)clistp->data; + cptr = threadp->name; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_thread_no = cur; + return TRUE; + } + } + } + cur--; + clistp = clistp->prev; + }while(clistp != threadlistp->prev); + clistp = threadlistp->prev; + cur = num; + do{ + if(cur < *sel_thread_no) + break; + + threadp = (nt_thread_tp)clistp->data; + cptr = threadp->name; + if(0 < wcstombs(buf, cptr, sizeof(buf))){ + if(0 == regexec(regexp, buf, + nmatch, pmatch, 0)){ + *sel_thread_no = cur; + return TRUE; + } + } + cur--; + clistp = clistp->prev; + }while(clistp != threadlistp->prev); + return FALSE; +} + diff --git a/src/ui/disp_win.c b/src/ui/disp_win.c index c855532..d8e40fc 100644 --- a/src/ui/disp_win.c +++ b/src/ui/disp_win.c @@ -29,6 +29,7 @@ nt_window_tp nt_disp_win_alloc(WINDOW *parent, winp->org_y = org_y; winp->data = 0; winp->cmd_param = cmd_param; + winp->status_msg = NULL; return winp; } diff --git a/src/utils/nt_std_t.c b/src/utils/nt_std_t.c index 6348181..0969d38 100644 --- a/src/utils/nt_std_t.c +++ b/src/utils/nt_std_t.c @@ -277,19 +277,9 @@ void nt_stack_free(nt_stack_tp ptr, nt_memfree_tp free_func) } if(ptr->linkp){ nt_all_link_free(ptr->linkp, free_func); - /*linkp = ptr->linkp; - do{ - (free_func)(linkp->data); - linkp = linkp->next; - }while(linkp != ptr->linkp);*/ } if(ptr->unlinkedp){ nt_all_link_free(ptr->unlinkedp, free_func); - /*linkp = ptr->unlinkedp; - do{ - (free_func)(linkp->data); - linkp = linkp->next; - }while(linkp != ptr->unlinkedp);*/ } free(ptr); } -- 2.11.0