📄 textbox.c
字号:
/* * $Id: textbox.c,v 1.45 2003/11/26 20:41:23 tom Exp $ * * textbox.c -- implements the text box * * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) * and: Thomas E. Dickey * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "dialog.h"typedef struct { DIALOG_CALLBACK obj; WINDOW *text; const char **buttons; int hscroll; char line[MAX_LEN + 1]; int fd; int file_size; int fd_bytes_read; int bytes_read; int buffer_len; bool begin_reached; bool buffer_first; bool end_reached; int page_length; int in_buf; /* index into buf[] */ char *buf;} MY_OBJ;static longlseek_obj(MY_OBJ * obj, long offset, int mode){ long fpos; if ((fpos = lseek(obj->fd, offset, mode)) == -1) { switch (mode) { case SEEK_CUR: dlg_exiterr("Cannot get file position"); break; case SEEK_END: dlg_exiterr("Cannot seek to end of file"); break; case SEEK_SET: dlg_exiterr("Cannot set file position to %ld", offset); break; } } return fpos;}static longftell_obj(MY_OBJ * obj){ return lseek_obj(obj, 0, SEEK_CUR);}static char *xalloc(long size){ char *result = malloc(size); assert_ptr(result, "xalloc"); return result;}/* * read_high() substitutes read() for tab->spaces conversion * * buffer_len, fd_bytes_read, bytes_read are modified * buf is allocated * * fd_bytes_read is the effective number of bytes read from file * bytes_read is the length of buf, that can be different if tab_correct */static voidread_high(MY_OBJ * obj, size_t size_read){ char *buftab, ch; int i = 0, j, n, begin_line, tmpint; /* Allocate space for read buffer */ buftab = xalloc(size_read + 1); if ((obj->fd_bytes_read = read(obj->fd, buftab, size_read)) != -1) { buftab[obj->fd_bytes_read] = '\0'; /* mark end of valid data */ if (dialog_vars.tab_correct) { /* calculate bytes_read by buftab and fd_bytes_read */ obj->bytes_read = begin_line = 0; for (j = 0; j < obj->fd_bytes_read; j++) if (buftab[j] == TAB) obj->bytes_read += dialog_state.tab_len - ((obj->bytes_read - begin_line) % dialog_state.tab_len); else if (buftab[j] == '\n') { obj->bytes_read++; begin_line = obj->bytes_read; } else obj->bytes_read++; if (obj->bytes_read > obj->buffer_len) { if (obj->buffer_first) obj->buffer_first = FALSE; /* disp = 0 */ else { free(obj->buf); } obj->buffer_len = obj->bytes_read; /* Allocate space for read buffer */ obj->buf = xalloc(obj->buffer_len + 1); } } else { if (obj->buffer_first) { obj->buffer_first = FALSE; /* Allocate space for read buffer */ obj->buf = xalloc(size_read + 1); } obj->bytes_read = obj->fd_bytes_read; } j = 0; begin_line = 0; while (j < obj->fd_bytes_read) if (((ch = buftab[j++]) == TAB) && (dialog_vars.tab_correct != 0)) { tmpint = dialog_state.tab_len - ((i - begin_line) % dialog_state.tab_len); for (n = 0; n < tmpint; n++) obj->buf[i++] = ' '; } else { if (ch == '\n') begin_line = i + 1; obj->buf[i++] = ch; } obj->buf[i] = '\0'; /* mark end of valid data */ } if (obj->bytes_read == -1) dlg_exiterr("Error reading file");}static inttabize(MY_OBJ * obj, int val, int pos){ long fpos; int i, count, begin_line; char *buftab; if (!dialog_vars.tab_correct) return val; fpos = ftell_obj(obj); lseek_obj(obj, fpos - obj->fd_bytes_read, SEEK_SET); /* Allocate space for read buffer */ buftab = xalloc(val + 1); if ((read(obj->fd, buftab, val)) == -1) dlg_exiterr("Error reading file in tabize()."); begin_line = count = 0; for (i = 0; i < val; i++) { if (pos && count >= val) { count = i; /* it's the retval */ break; } if (buftab[i] == TAB) count += dialog_state.tab_len - ((count - begin_line) % dialog_state.tab_len); else if (buftab[i] == '\n') { count++; begin_line = count; } else count++; } lseek_obj(obj, fpos, SEEK_SET); return count;}/* * Return current line of text. * 'page' should point to start of current line before calling, and will be * updated to point to start of next line. */static char *get_line(MY_OBJ * obj){ int i = 0; long fpos; obj->end_reached = FALSE; while (obj->buf[obj->in_buf] != '\n') { if (obj->buf[obj->in_buf] == '\0') { /* Either end of file or end of buffer reached */ fpos = ftell_obj(obj); if (fpos < obj->file_size) { /* Not end of file yet */ /* We've reached end of buffer, but not end of file yet, so * read next part of file into buffer */ read_high(obj, BUF_SIZE); obj->in_buf = 0; } else { if (!obj->end_reached) obj->end_reached = TRUE; break; } } else if (i < MAX_LEN) obj->line[i++] = obj->buf[obj->in_buf++]; else { if (i == MAX_LEN) /* Truncate lines longer than MAX_LEN characters */ obj->line[i++] = '\0'; obj->in_buf++; } } if (i <= MAX_LEN) obj->line[i] = '\0'; if (!obj->end_reached) obj->in_buf++; /* move pass '\n' */ return obj->line;}static boolmatch_string(MY_OBJ * obj, char *string){ char *match = get_line(obj); return strstr(match, string) != 0;}/* * Go back 'n' lines in text file. Called by dialog_textbox(). * 'in_buf' will be updated to point to the desired line in 'buf'. */static voidback_lines(MY_OBJ * obj, int n){ long fpos; int i, val_to_tabize; obj->begin_reached = FALSE; /* We have to distinguish between end_reached and !end_reached since at end * of file, the line is not ended by a '\n'. The code inside 'if' * basically does a '--in_buf' to move one character backward so as to * skip '\n' of the previous line */ if (!obj->end_reached) { /* Either beginning of buffer or beginning of file reached? */ if (obj->in_buf == 0) { fpos = ftell_obj(obj); if (fpos > obj->fd_bytes_read) { /* Not beginning of file yet */ /* We've reached beginning of buffer, but not beginning of file * yet, so read previous part of file into buffer. Note that * we only move backward for BUF_SIZE/2 bytes, but not BUF_SIZE * bytes to avoid re-reading again in print_page() later */ /* Really possible to move backward BUF_SIZE/2 bytes? */ if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) { /* No, move less then */ lseek_obj(obj, 0, SEEK_SET); val_to_tabize = fpos - obj->fd_bytes_read; } else { /* Move backward BUF_SIZE/2 bytes */ lseek_obj(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read), SEEK_CUR); val_to_tabize = BUF_SIZE / 2; } read_high(obj, BUF_SIZE); obj->in_buf = tabize(obj, val_to_tabize, 0); } else { /* Beginning of file reached */ obj->begin_reached = TRUE; return; } } obj->in_buf--; if (obj->buf[obj->in_buf] != '\n') /* Something's wrong... */ dlg_exiterr("Internal error in back_lines()."); } /* Go back 'n' lines */ for (i = 0; i < n; i++) { do { if (obj->in_buf == 0) { fpos = ftell_obj(obj); if (fpos > obj->fd_bytes_read) { /* Really possible to move backward BUF_SIZE/2 bytes? */ if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) { /* No, move less then */ lseek_obj(obj, 0, SEEK_SET); val_to_tabize = fpos - obj->fd_bytes_read; } else { /* Move backward BUF_SIZE/2 bytes */ lseek_obj(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read), SEEK_CUR); val_to_tabize = BUF_SIZE / 2; } read_high(obj, BUF_SIZE); obj->in_buf = tabize(obj, val_to_tabize, 0); } else { /* Beginning of file reached */ obj->begin_reached = TRUE; return; } } } while (obj->buf[--(obj->in_buf)] != '\n'); } obj->in_buf++;}/* * Print a new line of text. */static voidprint_line(MY_OBJ * obj, int row, int width){ int i, y, x; char *line; line = get_line(obj); line += MIN((int) strlen(line), obj->hscroll); /* Scroll horizontally */ (void) wmove(obj->text, row, 0); /* move cursor to correct line */ (void) waddch(obj->text, ' ');#ifdef NCURSES_VERSION (void) waddnstr(obj->text, line, MIN((int) strlen(line), width - 2));#else line[MIN((int) strlen(line), width - 2)] = '\0'; waddstr(obj->text, line);#endif getyx(obj->text, y, x); /* Clear 'residue' of previous line */ for (i = 0; i < width - x; i++) (void) waddch(obj->text, ' ');}/* * Print a new page of text. */static voidprint_page(MY_OBJ * obj, int height, int width){ int i, passed_end = 0; obj->page_length = 0; for (i = 0; i < height; i++) { print_line(obj, i, width); if (!passed_end) obj->page_length++; if (obj->end_reached && !passed_end) passed_end = 1; } (void) wnoutrefresh(obj->text);}/* * Print current position */static voidprint_position(MY_OBJ * obj, WINDOW *win, int height, int width){ long fpos; int percent; fpos = ftell_obj(obj); wattrset(win, position_indicator_attr); percent = !obj->file_size ? 100 : ((fpos - obj->fd_bytes_read + tabize(obj, obj->in_buf, 1)) * 100) / obj->file_size; (void) wmove(win, height - 3, width - 9); (void) wprintw(win, "(%3d%%)", percent); dlg_draw_arrows(win, TRUE, TRUE, 5, 0, height - 3);}/* * Display a dialog box and get the search term from user */static intget_search_term(WINDOW *dialog, char *input, int height, int width){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -