📄 textarea.c
字号:
/* Textarea form item handlers *//* $Id: textarea.c,v 1.143.2.2 2005/05/01 22:03:23 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifndef _GNU_SOURCE#define _GNU_SOURCE /* XXX: we want memrchr() ! */#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "elinks.h"#include "bfu/dialog.h"#include "document/document.h"#include "document/forms.h"#include "document/html/parser.h"#include "document/html/renderer.h"#include "document/view.h"#include "intl/gettext/libintl.h"#include "sched/session.h"#include "terminal/draw.h"#include "terminal/window.h"#include "util/error.h"#include "util/file.h"#include "util/memory.h"#include "util/string.h"#include "viewer/text/form.h"#include "viewer/text/textarea.h"#include "viewer/text/view.h"struct line_info { int start; int end;};/* We add two extra entries to the table so the ending info can be added * without reallocating. */#define realloc_line_info(info, size) \ mem_align_alloc(info, size, (size) + 3, struct line_info, 0xFF)/* Allocates a line_info table describing the layout of the textarea buffer. * * @width is max width and the offset at which text will be wrapped * @wrap controls how the wrapping of text is performed * @format is non zero the @text will be modified to make it suitable for * encoding it for form posting */static struct line_info *format_text(unsigned char *text, int width, enum form_wrap wrap, int format){ struct line_info *line = NULL; int line_number = 0; int begin = 0; int pos = 0; int skip; assert(text); if_assert_failed return NULL; /* Allocate the ending entries */ if (!realloc_line_info(&line, 0)) return NULL; while (text[pos]) { if (text[pos] == '\n') { skip = 1; } else if (wrap == FORM_WRAP_NONE || pos - begin < width) { pos++; continue; } else { unsigned char *wrappos; /* Find a place to wrap the text */ wrappos = memrchr(&text[begin], ' ', pos - begin); if (wrappos) { /* When formatting text for form submitting we * have to apply the wrapping mode. */ if (wrap == FORM_WRAP_HARD && format) *wrappos = '\n'; pos = wrappos - text; } skip = !!wrappos; } if (!realloc_line_info(&line, line_number)) { mem_free_if(line); return NULL; } line[line_number].start = begin; line[line_number++].end = pos; begin = pos += skip; } /* Flush the last text before the loop ended */ line[line_number].start = begin; line[line_number++].end = pos; /* Add end marker */ line[line_number].start = line[line_number].end = -1; return line;}/* Searches for @cursor_position (aka. position in the fs->value string) for * the corresponding entry in the @line info. Returns the index or -1 if * position is not found. */static intget_textarea_line_number(struct line_info *line, int cursor_position){ int idx; for (idx = 0; line[idx].start != -1; idx++) { int wrap; if (cursor_position < line[idx].start) continue; wrap = (line[idx + 1].start == line[idx].end); if (cursor_position >= line[idx].end + !wrap) continue; return idx; } return -1;}/* Fixes up the vpos and vypos members of the form_state. Returns the * logical position in the textarea view. */intarea_cursor(struct form_control *fc, struct form_state *fs){ struct line_info *line; int x, y; assert(fc && fs); if_assert_failed return 0; line = format_text(fs->value, fc->cols, fc->wrap, 0); if (!line) return 0; y = get_textarea_line_number(line, fs->state); if (y == -1) { mem_free(line); return 0; } x = fs->state - line[y].start; mem_free(line); if (fc->wrap && x == fc->cols) x--; int_bounds(&fs->vpos, x - fc->cols + 1, x); int_bounds(&fs->vypos, y - fc->rows + 1, y); x -= fs->vpos; y -= fs->vypos; return y * fc->cols + x;}voiddraw_textarea(struct terminal *term, struct form_state *fs, struct document_view *doc_view, struct link *link){ struct line_info *line, *linex; struct form_control *fc; struct box *box; int vx, vy; int sl, ye; int x, y; assert(term && doc_view && doc_view->document && doc_view->vs && link); if_assert_failed return; fc = get_link_form_control(link); assertm(fc, "link %d has no form control", (int) (link - doc_view->document->links)); if_assert_failed return; box = &doc_view->box; vx = doc_view->vs->x; vy = doc_view->vs->y; if (!link->npoints) return; area_cursor(fc, fs); linex = format_text(fs->value, fc->cols, fc->wrap, 0); if (!linex) return; line = linex; sl = fs->vypos; while (line->start != -1 && sl) sl--, line++; x = link->points[0].x + box->x - vx; y = link->points[0].y + box->y - vy; ye = y + fc->rows; for (; line->start != -1 && y < ye; line++, y++) { int i; if (!row_is_in_box(box, y)) continue; for (i = 0; i < fc->cols; i++) { unsigned char data; int xi = x + i; if (!col_is_in_box(box, xi)) continue; if (i >= -fs->vpos && i + fs->vpos < line->end - line->start) data = fs->value[line->start + i + fs->vpos]; else data = '_'; draw_char_data(term, xi, y, data); } } for (; y < ye; y++) { int i; if (!row_is_in_box(box, y)) continue; for (i = 0; i < fc->cols; i++) { int xi = x + i; if (col_is_in_box(box, xi)) draw_char_data(term, xi, y, '_'); } } mem_free(linex);}unsigned char *encode_textarea(struct submitted_value *sv){ struct form_control *fc; struct string newtext; void *blabla; int i; assert(sv && sv->value); if_assert_failed return NULL; fc = sv->form_control; /* We need to reformat text now if it has to be wrapped hard, just * before encoding it. */ blabla = format_text(sv->value, fc->cols, fc->wrap, 1); mem_free_if(blabla); if (!init_string(&newtext)) return NULL; for (i = 0; sv->value[i]; i++) { if (sv->value[i] != '\n') add_char_to_string(&newtext, sv->value[i]); else add_crlf_to_string(&newtext); } return newtext.source;}/* We use some evil hacking in order to make external textarea editor working. * We need to have some way how to be notified that the editor finished and we * should reload content of the textarea. So we use global variable * textarea_editor as a flag whether we have one running, and if we have, we * just call textarea_edit(1, ...). Then we recover our state from static * variables, reload content of textarea back from file and clean up. * * Unfortunately, we can't support calling of editor from non-master links * session, as it would be extremely ugly to hack (you would have to transfer * the content of it back to master somehow, add special flags for not deleting * of 'delete' etc) and I'm not going to do that now. Inter-links communication * *NEEDS* rewrite, as it looks just like quick messy hack now. --pasky */int textarea_editor = 0;static unsigned char *save_textarea_file(unsigned char *value){ unsigned char *filename; FILE *file = NULL; int h; filename = get_tempdir_filename("elinks-area-XXXXXX"); if (!filename) return NULL; h = safe_mkstemp(filename); if (h >= 0) file = fdopen(h, "w"); if (file) { fwrite(value, strlen(value), 1, file); fclose(file); } else { mem_free(filename); } return filename;}static unsigned char *load_textarea_file(unsigned char *filename, int maxlength){ unsigned char *value = NULL; FILE *file = fopen(filename, "rb+"); int filelen = -1; if (!file) return NULL; if (!fseek(file, 0, SEEK_END)) { filelen = ftell(file); if (filelen != -1 && fseek(file, 0, SEEK_SET)) filelen = -1; } if (filelen >= 0 && filelen <= maxlength) { int bread; value = mem_alloc(filelen + 1); if (value) { bread = fread(value, 1, filelen, file); value[bread] = 0; } } fclose(file);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -