📄 form.c
字号:
/* Forms viewing/manipulation handling *//* $Id: form.c,v 1.264.2.5 2005/04/06 08:59:39 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifndef _GNU_SOURCE#define _GNU_SOURCE /* XXX: we want memrchr() ! */#endif#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h> /* OS/2 needs this after sys/types.h */#endif#include "elinks.h"#include "bfu/listmenu.h"#include "bfu/dialog.h"#include "config/kbdbind.h"#include "dialogs/menu.h"#include "document/document.h"#include "document/forms.h"#include "document/html/parser.h"#include "document/view.h"#include "intl/gettext/libintl.h"#include "formhist/formhist.h"#include "mime/mime.h"#include "osdep/ascii.h"#include "osdep/osdep.h"#include "protocol/uri.h"#include "sched/action.h"#include "sched/session.h"#include "terminal/terminal.h"#include "terminal/window.h"#include "util/conv.h"#include "util/error.h"#include "util/file.h"#include "util/memory.h"#include "util/string.h"#include "viewer/text/draw.h"#include "viewer/text/form.h"#include "viewer/text/link.h"#include "viewer/text/textarea.h"#include "viewer/text/view.h"#include "viewer/text/vs.h"/* TODO: Some of these (particulary those encoding routines) would feel better * in viewer/common/. --pasky */struct submitted_value *init_submitted_value(unsigned char *name, unsigned char *value, enum form_type type, struct form_control *fc, int position){ struct submitted_value *sv; sv = mem_alloc(sizeof(*sv)); if (!sv) return NULL; sv->value = stracpy(value); if (!sv->value) { mem_free(sv); return NULL; } sv->name = stracpy(name); if (!sv->name) { mem_free(sv->value); mem_free(sv); return NULL; } sv->type = type; sv->form_control = fc; sv->position = position; return sv;}voiddone_submitted_value(struct submitted_value *sv){ if (!sv) return; mem_free_if(sv->value); mem_free_if(sv->name); mem_free(sv);}static voidfixup_select_state(struct form_control *fc, struct form_state *fs){ int i; assert(fc && fs); if_assert_failed return; if (fs->state >= 0 && fs->state < fc->nvalues && !strcmp(fc->values[fs->state], fs->value)) return; for (i = 0; i < fc->nvalues; i++) if (!strcmp(fc->values[i], fs->value)) { fs->state = i; return; } fs->state = 0; mem_free_set(&fs->value, stracpy(fc->nvalues ? fc->values[0] : (unsigned char *) ""));}/* menu_func */voidselected_item(struct terminal *term, void *item_, void *ses_){ struct session *ses = ses_; int item = (long) item_; struct document_view *doc_view; struct link *link; struct form_state *fs; struct form_control *fc; assert(term && ses); if_assert_failed return; doc_view = current_frame(ses); assert(doc_view && doc_view->vs && doc_view->document); if_assert_failed return; link = get_current_link(doc_view); if (!link || link->type != LINK_SELECT) return; fc = get_link_form_control(link); fs = find_form_state(doc_view, fc); if (fs) { if (item >= 0 && item < fc->nvalues) { fs->state = item; mem_free_set(&fs->value, stracpy(fc->values[item])); } fixup_select_state(fc, fs); } refresh_view(ses, doc_view, 0);}static voidinit_form_state(struct form_control *fc, struct form_state *fs){ assert(fc && fs); if_assert_failed return; mem_free_set(&fs->value, NULL); switch (fc->type) { case FC_TEXT: case FC_PASSWORD: case FC_TEXTAREA: fs->value = stracpy(fc->default_value); fs->state = strlen(fc->default_value); fs->vpos = 0; break; case FC_FILE: fs->value = stracpy(""); fs->state = 0; fs->vpos = 0; break; case FC_SELECT: fs->value = stracpy(fc->default_value); fs->state = fc->default_state; fixup_select_state(fc, fs); break; case FC_CHECKBOX: case FC_RADIO: fs->state = fc->default_state; /* Fall-through */ case FC_SUBMIT: case FC_IMAGE: case FC_RESET: case FC_BUTTON: case FC_HIDDEN: fs->value = stracpy(fc->default_value); break; }}struct form_state *find_form_state(struct document_view *doc_view, struct form_control *fc){ struct view_state *vs; struct form_state *fs; int n; assert(doc_view && doc_view->vs && fc); if_assert_failed return NULL; vs = doc_view->vs; n = fc->g_ctrl_num; if (n >= vs->form_info_len) { int nn = n + 1; fs = mem_realloc(vs->form_info, nn * sizeof(*fs)); if (!fs) return NULL; memset(fs + vs->form_info_len, 0, (nn - vs->form_info_len) * sizeof(*fs)); vs->form_info = fs; vs->form_info_len = nn; } fs = &vs->form_info[n]; if (fs->form_view && fs->form_view->form_num == fc->form->form_num && fs->g_ctrl_num == fc->g_ctrl_num && fs->position == fc->position && fs->type == fc->type) return fs; mem_free_if(fs->value); memset(fs, 0, sizeof(*fs)); fs->form_view = find_form_view(doc_view, fc->form); fs->g_ctrl_num = fc->g_ctrl_num; fs->position = fc->position; fs->type = fc->type; init_form_state(fc, fs); return fs;}struct form_control *find_form_control(struct document *document, struct form_state *fs){ struct form *form = find_form_by_form_view(document, fs->form_view); struct form_control *fc; foreach (fc, form->items) { if (fs->g_ctrl_num == fc->g_ctrl_num && fs->position == fc->position && fs->type == fc->type) return fc; } return NULL;}struct form_view *find_form_view_in_vs(struct view_state *vs, int form_num){ struct form_view *fv; assert(vs); foreach (fv, vs->forms) if (fv->form_num == form_num) return fv; fv = mem_calloc(1, sizeof(*fv)); fv->form_num = form_num; add_to_list(vs->forms, fv); return fv;}struct form_view *find_form_view(struct document_view *doc_view, struct form *form){ return find_form_view_in_vs(doc_view->vs, form->form_num);}struct form *find_form_by_form_view(struct document *document, struct form_view *fv){ struct form *form; foreach (form, document->forms) { if (form->form_num == fv->form_num) return form; } return NULL;}intget_current_state(struct session *ses){ struct document_view *doc_view; struct link *link; struct form_state *fs; assert(ses); if_assert_failed return -1; doc_view = current_frame(ses); assert(doc_view && doc_view->vs && doc_view->document); if_assert_failed return -1; link = get_current_link(doc_view); if (!link || link->type != LINK_SELECT) return -1; fs = find_form_state(doc_view, get_link_form_control(link)); if (fs) return fs->state; return -1;}voiddraw_form_entry(struct terminal *term, struct document_view *doc_view, struct link *link){ struct form_state *fs; struct form_control *fc; struct view_state *vs; struct box *box; int dx, dy; 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; fs = find_form_state(doc_view, fc); if (!fs) return; box = &doc_view->box; vs = doc_view->vs; dx = box->x - vs->x; dy = box->y - vs->y; switch (fc->type) { unsigned char *s; int len; int i, x, y; case FC_TEXT: case FC_PASSWORD: case FC_FILE: int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state); if (!link->npoints) break; y = link->points[0].y + dy; if (!row_is_in_box(box, y)) break; len = strlen(fs->value) - fs->vpos; x = link->points[0].x + dx; for (i = 0; i < fc->size; i++, x++) { unsigned char data; if (!col_is_in_box(box, x)) continue; if (fs->value && i >= -fs->vpos && i < len) data = fc->type != FC_PASSWORD ? fs->value[i + fs->vpos] : '*'; else data = '_'; draw_char_data(term, x, y, data); } break; case FC_TEXTAREA: draw_textarea(term, fs, doc_view, link); break; case FC_CHECKBOX: case FC_RADIO: if (link->npoints < 2) break; x = link->points[1].x + dx; y = link->points[1].y + dy; if (is_in_box(box, x, y)) draw_char_data(term, x, y, fs->state ? 'X' : ' '); break; case FC_SELECT: fixup_select_state(fc, fs); if (fs->state < fc->nvalues) s = fc->labels[fs->state]; else /* XXX: when can this happen? --pasky */ s = ""; len = s ? strlen(s) : 0; for (i = 0; i < link->npoints; i++) { x = link->points[i].x + dx; y = link->points[i].y + dy; if (is_in_box(box, x, y)) draw_char_data(term, x, y, i < len ? s[i] : '_'); } break; case FC_SUBMIT: case FC_IMAGE: case FC_RESET: case FC_BUTTON: case FC_HIDDEN: break; }}voiddraw_forms(struct terminal *term, struct document_view *doc_view){ struct link *l1, *l2; assert(term && doc_view); if_assert_failed return; l1 = get_first_link(doc_view); l2 = get_last_link(doc_view); if (!l1 || !l2) { assertm(!l1 && !l2, "get_first_link == %p, get_last_link == %p", l1, l2); /* Return path :-). */ return; } do { struct form_control *fc = get_link_form_control(l1); if (!fc) continue;#ifdef CONFIG_FORMHIST if (fc->type == FC_TEXT || fc->type == FC_PASSWORD) { unsigned char *value; assert(fc->form); value = get_form_history_value(fc->form->action, fc->name); if (value) mem_free_set(&fc->default_value, stracpy(value)); }#endif /* CONFIG_FORMHIST */ draw_form_entry(term, doc_view, l1); } while (l1++ < l2);}voiddone_submitted_value_list(struct list_head *list){ struct submitted_value *sv, *svtmp; assert(list); if_assert_failed return; foreach (sv, *list) { svtmp = sv; sv = sv->prev; del_from_list(svtmp); done_submitted_value(svtmp); }}static voidadd_submitted_value_to_list(struct form_control *fc, struct form_state *fs, struct list_head *list){ struct submitted_value *sub; unsigned char *name; enum form_type type; int position; assert(fc && fs && list); name = fc->name; position = fc->position; type = fc->type; switch (fc->type) { case FC_TEXT: case FC_PASSWORD: case FC_FILE: case FC_TEXTAREA: sub = init_submitted_value(name, fs->value, type, fc, position); if (sub) add_to_list(*list, sub); break; case FC_CHECKBOX: case FC_RADIO: if (!fs->state) break; /* fall through */ case FC_SUBMIT: case FC_HIDDEN: case FC_RESET: case FC_BUTTON: sub = init_submitted_value(name, fs->value, type, fc, position); if (sub) add_to_list(*list, sub); break; case FC_SELECT: if (!fc->nvalues) break; fixup_select_state(fc, fs); sub = init_submitted_value(name, fs->value, type, fc, position); if (sub) add_to_list(*list, sub); break; case FC_IMAGE: name = straconcat(fc->name, ".x", NULL); if (!name) break; sub = init_submitted_value(name, "0", type, fc, position); mem_free(name); if (sub) add_to_list(*list, sub); name = straconcat(fc->name, ".y", NULL); if (!name) break; sub = init_submitted_value(name, "0", type, fc, position); mem_free(name); if (sub) add_to_list(*list, sub); break; }}static voidsort_submitted_values(struct list_head *list){ int changed; do { struct submitted_value *sub, *next; changed = 0; foreach (sub, *list) if (list_has_next(*list, sub)) if (sub->next->position < sub->position) { next = sub->next; del_from_list(sub); add_at_pos(next, sub); sub = next; changed = 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -