summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2003-10-25 00:35:49 +0000
committerJames Bursa <james@netsurf-browser.org>2003-10-25 00:35:49 +0000
commitf1375fe19db064fcebf00433ce73eab99be038ef (patch)
tree19e239a41a8a68baab5b444447adc3aae5bf04fa /render
parent099d537267e8e4114128e59e2614c99d77dd4feb (diff)
downloadnetsurf-f1375fe19db064fcebf00433ce73eab99be038ef.tar.gz
netsurf-f1375fe19db064fcebf00433ce73eab99be038ef.tar.bz2
[project @ 2003-10-25 00:35:49 by bursa]
Split out and clean up form submit code. svn path=/import/netsurf/; revision=374
Diffstat (limited to 'render')
-rw-r--r--render/box.c164
-rw-r--r--render/box.h63
-rw-r--r--render/form.c175
-rw-r--r--render/form.h89
4 files changed, 328 insertions, 163 deletions
diff --git a/render/box.c b/render/box.c
index 77fc99f00..3ad80ffad 100644
--- a/render/box.c
+++ b/render/box.c
@@ -18,6 +18,7 @@
#include "netsurf/css/css.h"
#include "netsurf/render/box.h"
#include "netsurf/render/font.h"
+#include "netsurf/render/form.h"
#include "netsurf/render/html.h"
#ifdef riscos
#include "netsurf/desktop/gui.h"
@@ -70,7 +71,7 @@ static struct box *box_input_text(xmlNode *n, struct status *status,
struct css_style *style, bool password);
static struct result box_button(xmlNode *n, struct status *status,
struct css_style *style);
-static void add_option(xmlNode* n, struct gui_gadget* current_select, char *text);
+static void add_option(xmlNode* n, struct form_control* current_select, char *text);
static void box_normalise_block(struct box *block);
static void box_normalise_table(struct box *table);
void box_normalise_table_row_group(struct box *row_group,
@@ -78,7 +79,7 @@ void box_normalise_table_row_group(struct box *row_group,
void box_normalise_table_row(struct box *row,
unsigned int **row_span, unsigned int *table_columns);
static void box_normalise_inline_container(struct box *cont);
-static void gadget_free(struct gui_gadget* g);
+static void gadget_free(struct form_control* g);
static void box_free_box(struct box *box);
static struct result box_object(xmlNode *n, struct status *status,
struct css_style *style);
@@ -88,9 +89,8 @@ static struct result box_applet(xmlNode *n, struct status *status,
struct css_style *style);
static struct result box_iframe(xmlNode *n, struct status *status,
struct css_style *style);
-static struct form* create_form(xmlNode* n);
static void add_form_element(struct page_elements* pe, struct form* f);
-static void add_gadget_element(struct page_elements* pe, struct gui_gadget* g);
+static void add_gadget_element(struct page_elements* pe, struct form_control* g);
static bool plugin_decode(struct content* content, char* url, struct box* box,
struct object_params* po);
@@ -370,7 +370,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
}
box = box_create(parent_style, status.href, title);
- box->text = text;
+ box->text = text;
box->style_clone = 1;
box->length = strlen(text);
if (text[box->length - 1] == ' ') {
@@ -653,7 +653,7 @@ struct css_style * box_get_style(struct content ** stylesheet,
xmlFree(s);
}
}
-
+
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) {
struct css_style * astyle = xcalloc(1, sizeof(struct css_style));
memcpy(astyle, &css_empty_style, sizeof(struct css_style));
@@ -737,9 +737,27 @@ struct result box_image(xmlNode *n, struct status *status,
struct result box_form(xmlNode *n, struct status *status,
struct css_style *style)
{
+ char* s;
struct box *box;
+ struct form *form;
+
box = box_create(style, status->href, status->title);
- status->current_form = create_form(n);
+
+ status->current_form = form = xcalloc(1, sizeof(*form));
+
+ if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) {
+ form->action = s;
+ }
+
+ form->method = method_GET;
+ if ((s = (char *) xmlGetProp(n, (const xmlChar *) "method"))) {
+ if (stricmp(s, "post") == 0)
+ form->method = method_POST;
+ xmlFree(s);
+ }
+
+ form->controls = form->last_control = 0;
+
add_form_element(status->elements, status->current_form);
return (struct result) {box, 1};
}
@@ -752,10 +770,10 @@ struct result box_textarea(xmlNode *n, struct status *status,
char* s;
box = box_create(style, NULL, 0);
- box->gadget = xcalloc(1, sizeof(struct gui_gadget));
+ box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget->box = box;
box->gadget->type = GADGET_TEXTAREA;
- box->gadget->form = status->current_form;
+ form_add_control(status->current_form, box->gadget);
style->display = CSS_DISPLAY_INLINE_BLOCK;
/* split the content at newlines and make an inline container with an
@@ -800,12 +818,12 @@ struct result box_select(xmlNode *n, struct status *status,
struct box *box;
struct box *inline_container;
struct box *inline_box;
- struct gui_gadget *gadget = xcalloc(1, sizeof(struct gui_gadget));
+ struct form_control *gadget = xcalloc(1, sizeof(struct form_control));
char* s;
xmlNode *c, *c2;
gadget->type = GADGET_SELECT;
- gadget->form = status->current_form;
+ form_add_control(status->current_form, gadget);
gadget->data.select.multiple = false;
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "multiple"))) {
@@ -882,9 +900,9 @@ struct result box_select(xmlNode *n, struct status *status,
return (struct result) {box, 0};
}
-void add_option(xmlNode* n, struct gui_gadget* current_select, char *text)
+void add_option(xmlNode* n, struct form_control* current_select, char *text)
{
- struct formoption *option = xcalloc(1, sizeof(struct formoption));
+ struct form_option *option = xcalloc(1, sizeof(struct form_option));
char *s, *c;
assert(current_select != 0);
@@ -922,7 +940,7 @@ struct result box_input(xmlNode *n, struct status *status,
struct css_style *style)
{
struct box* box = 0;
- struct gui_gadget *gadget = 0;
+ struct form_control *gadget = 0;
char *s, *type, *url;
type = (char *) xmlGetProp(n, (const xmlChar *) "type");
@@ -943,16 +961,16 @@ struct result box_input(xmlNode *n, struct status *status,
else if (stricmp(type, "hidden") == 0)
{
/* no box for hidden inputs */
- gadget = xcalloc(1, sizeof(struct gui_gadget));
+ gadget = xcalloc(1, sizeof(struct form_control));
gadget->type = GADGET_HIDDEN;
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value")))
- gadget->data.hidden.value = s;
+ gadget->value = s;
}
else if (stricmp(type, "checkbox") == 0 || stricmp(type, "radio") == 0)
{
box = box_create(style, NULL, 0);
- box->gadget = gadget = xcalloc(1, sizeof(struct gui_gadget));
+ box->gadget = gadget = xcalloc(1, sizeof(struct form_control));
gadget->box = box;
if (type[0] == 'c' || type[0] == 'C')
gadget->type = GADGET_CHECKBOX;
@@ -967,12 +985,8 @@ struct result box_input(xmlNode *n, struct status *status,
xmlFree(s);
}
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) {
- if (gadget->type == GADGET_CHECKBOX)
- gadget->data.checkbox.value = s;
- else
- gadget->data.radio.value = s;
- }
+ if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value")))
+ gadget->value = s;
}
else if (stricmp(type, "submit") == 0 || stricmp(type, "reset") == 0)
{
@@ -998,33 +1012,21 @@ struct result box_input(xmlNode *n, struct status *status,
else if (stricmp(type, "image") == 0)
{
box = box_create(style, NULL, 0);
- box->gadget = gadget = xcalloc(1, sizeof(struct gui_gadget));
+ box->gadget = gadget = xcalloc(1, sizeof(struct form_control));
gadget->box = box;
gadget->type = GADGET_IMAGE;
- if ((s = (char *) xmlGetProp(n, (const xmlChar*) "name"))) {
- gadget->data.image.n = s;
- }
- if ((s = (char *) xmlGetProp(n, (const xmlChar*) "width"))) {
- gadget->data.image.width = (atoi(s));
- }
- if ((s = (char *) xmlGetProp(n, (const xmlChar*) "height"))) {
- gadget->data.image.height = (atoi(s));
- }
if ((s = (char *) xmlGetProp(n, (const xmlChar*) "src"))) {
- url = url_join(strdup(s), status->content->url);
+ url = url_join(s, status->content->url);
html_fetch_object(status->content, url, box);
+ xmlFree(s);
}
- gadget->data.image.name =
- xcalloc(strlen(gadget->data.image.n) + 5, sizeof(char));
- gadget->data.image.value =
- xcalloc(strlen(gadget->data.image.n) + 20, sizeof(char));
}
if (type != 0)
xmlFree(type);
if (gadget != 0) {
- gadget->form = status->current_form;
+ form_add_control(status->current_form, gadget);
gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name");
add_gadget_element(status->elements, gadget);
}
@@ -1041,7 +1043,7 @@ struct box *box_input_text(xmlNode *n, struct status *status,
struct box *inline_container, *inline_box;
style->display = CSS_DISPLAY_INLINE_BLOCK;
- box->gadget = xcalloc(1, sizeof(struct gui_gadget));
+ box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget->box = box;
box->gadget->maxlength = 100;
@@ -1090,10 +1092,10 @@ struct result box_button(xmlNode *n, struct status *status,
style->display = CSS_DISPLAY_INLINE_BLOCK;
if (!type || strcasecmp(type, "submit") == 0) {
- box->gadget = xcalloc(1, sizeof(struct gui_gadget));
+ box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget->type = GADGET_SUBMIT;
} else if (strcasecmp(type, "reset") == 0) {
- box->gadget = xcalloc(1, sizeof(struct gui_gadget));
+ box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget->type = GADGET_RESET;
} else {
/* type="button" or unknown: just render the contents */
@@ -1104,7 +1106,7 @@ struct result box_button(xmlNode *n, struct status *status,
if (type)
xmlFree(type);
- box->gadget->form = status->current_form;
+ form_add_control(status->current_form, box->gadget);
box->gadget->box = box;
box->gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name");
box->gadget->value = (char *) xmlGetProp(n, (const xmlChar *) "value");
@@ -1561,50 +1563,27 @@ void box_normalise_inline_container(struct box *cont)
}
-void gadget_free(struct gui_gadget* g)
+void gadget_free(struct form_control* g)
{
- struct formoption *o, *o1;
+ struct form_option *o, *o1;
if (g->name != 0)
xmlFree(g->name);
free(g->value);
free(g->initial_value);
- switch (g->type)
- {
- case GADGET_HIDDEN:
- if (g->data.hidden.value != 0)
- xmlFree(g->data.hidden.value);
- break;
- case GADGET_RADIO:
- if (g->data.checkbox.value != 0)
- xmlFree(g->data.radio.value);
- break;
- case GADGET_CHECKBOX:
- if (g->data.checkbox.value != 0)
- xmlFree(g->data.checkbox.value);
- break;
- case GADGET_IMAGE:
- if (g->data.image.n != 0)
- xmlFree(g->data.image.n);
- if (g->data.image.name != 0)
- xfree(g->data.image.name);
- if (g->data.image.value != 0)
- xfree(g->data.image.value);
- break;
- case GADGET_SELECT:
- o = g->data.select.items;
- while (o != NULL)
- {
- if (o->text != 0)
- xmlFree(o->text);
- if (o->value != 0)
- xmlFree(o->value);
- o1 = o->next;
- xfree(o);
- o = o1;
- }
- break;
+ if (g->type == GADGET_SELECT) {
+ o = g->data.select.items;
+ while (o != NULL)
+ {
+ if (o->text != 0)
+ xmlFree(o->text);
+ if (o->value != 0)
+ xmlFree(o->value);
+ o1 = o->next;
+ xfree(o);
+ o = o1;
+ }
}
}
@@ -1649,27 +1628,6 @@ void box_free_box(struct box *box)
* form helper functions
*/
-struct form* create_form(xmlNode* n)
-{
- struct form* form;
- char* s;
-
- form = xcalloc(1, sizeof(*form));
-
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) {
- form->action = s;
- }
-
- form->method = method_GET;
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "method"))) {
- if (stricmp(s, "post") == 0)
- form->method = method_POST;
- xmlFree(s);
- }
-
- return form;
-}
-
void add_form_element(struct page_elements* pe, struct form* f)
{
pe->forms = xrealloc(pe->forms, (pe->numForms + 1) * sizeof(struct form*));
@@ -1677,9 +1635,9 @@ void add_form_element(struct page_elements* pe, struct form* f)
pe->numForms++;
}
-void add_gadget_element(struct page_elements* pe, struct gui_gadget* g)
+void add_gadget_element(struct page_elements* pe, struct form_control* g)
{
- pe->gadgets = xrealloc(pe->gadgets, (pe->numGadgets + 1) * sizeof(struct gui_gadget*));
+ pe->gadgets = xrealloc(pe->gadgets, (pe->numGadgets + 1) * sizeof(struct form_control*));
pe->gadgets[pe->numGadgets] = g;
pe->numGadgets++;
}
diff --git a/render/box.h b/render/box.h
index 76c9500c9..2c76f3ffd 100644
--- a/render/box.h
+++ b/render/box.h
@@ -33,59 +33,8 @@ struct column {
unsigned long min, max, width;
};
-struct formoption {
- bool selected;
- bool initial_selected;
- char* value;
- char* text;
- struct formoption* next;
-};
-
struct box;
-struct gui_gadget {
- enum { GADGET_HIDDEN = 0, GADGET_TEXTBOX, GADGET_RADIO, GADGET_CHECKBOX,
- GADGET_SELECT, GADGET_TEXTAREA,
- GADGET_IMAGE, GADGET_PASSWORD, GADGET_SUBMIT, GADGET_RESET } type;
- char *name;
- char *value;
- char *initial_value;
- struct form *form;
- struct box *box;
- struct box *caret_inline_container;
- struct box *caret_text_box;
- int caret_char_offset;
- unsigned int maxlength;
- union {
- struct {
- char* value;
- } hidden;
- struct {
- char* name;
- char* value;
- char* n;
- int width, height;
- int mx, my;
- } image;
- struct {
- int num_items;
- struct formoption *items, *last_item;
- bool multiple;
- int num_selected;
- /** Currently selected item, if num_selected == 1. */
- struct formoption *current;
- } select;
- struct {
- int selected;
- char* value;
- } checkbox;
- struct {
- int selected;
- char* value;
- } radio;
- } data;
-};
-
/* parameters for <object> and related elements */
struct object_params {
char* data;
@@ -137,28 +86,22 @@ struct box {
struct box * next_float;
struct column *col;
struct font_data *font;
- struct gui_gadget* gadget;
+ struct form_control* gadget;
struct content* object; /* usually an image */
struct object_params *object_params;
void* object_state; /* state of any object */
};
-struct form
-{
- char* action; /* url */
- enum {method_GET, method_POST} method;
-};
-
struct formsubmit
{
struct form* form;
- struct gui_gadget* items;
+ struct form_control* items;
};
struct page_elements
{
struct form** forms;
- struct gui_gadget** gadgets;
+ struct form_control** gadgets;
struct img** images;
int numForms;
int numGadgets;
diff --git a/render/form.c b/render/form.c
new file mode 100644
index 000000000..f4ed0a9f8
--- /dev/null
+++ b/render/form.c
@@ -0,0 +1,175 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2003 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
+ */
+
+/** \file
+ * Form handling functions (implementation).
+ */
+
+#include <assert.h>
+#include <string.h>
+#include "curl/curl.h"
+#include "netsurf/render/form.h"
+#include "netsurf/utils/utils.h"
+
+
+/**
+ * Add a control to the list of controls in a form.
+ */
+
+void form_add_control(struct form *form, struct form_control *control)
+{
+ control->form = form;
+ if (form->controls) {
+ assert(form->last_control);
+ form->last_control->next = control;
+ control->next = 0;
+ form->last_control = control;
+ } else {
+ form->controls = form->last_control = control;
+ }
+}
+
+
+/**
+ * Identify 'successful' controls.
+ *
+ * See HTML 4.01 section 17.13.2.
+ */
+
+struct form_successful_control *form_successful_controls(struct form *form,
+ struct form_control *submit_button)
+{
+ struct form_control *control;
+ struct form_option *option;
+ struct form_successful_control sentinel, *last_success;
+ last_success = &sentinel;
+
+ for (control = form->controls; control; control = control->next) {
+ struct form_successful_control *success_new;
+
+ /* ignore disabled controls */
+ if (control->disabled)
+ continue;
+
+ /* ignore controls with no name */
+ if (!control->name)
+ continue;
+
+ /* only the activated submit button is successful */
+ if (control->type == GADGET_SUBMIT && control != submit_button)
+ continue;
+
+ /* ignore checkboxes and radio buttons which aren't selected */
+ if (control->type == GADGET_CHECKBOX && !control->data.checkbox.selected)
+ continue;
+ if (control->type == GADGET_RADIO && !control->data.radio.selected)
+ continue;
+
+ /* select */
+ if (control->type == GADGET_SELECT) {
+ for (option = control->data.select.items; option;
+ option = option->next) {
+ if (option->selected && option->value) {
+ success_new = xcalloc(1, sizeof(*success_new));
+ success_new->name = xstrdup(control->name);
+ success_new->value = xstrdup(option->value);
+ success_new->next = 0;
+ last_success->next = success_new;
+ last_success = success_new;
+ }
+ }
+ continue;
+ }
+
+ /* textarea */
+ if (control->type == GADGET_TEXTAREA) {
+ /* TODO */
+ continue;
+ }
+
+ /* image */
+ if (control->type == GADGET_IMAGE) {
+ int len = strlen(control->name) + 3;
+ /* x */
+ success_new = xcalloc(1, sizeof(*success_new));
+ success_new->name = xcalloc(1, len);
+ sprintf(success_new->name, "%s.x", control->name);
+ success_new->value = xcalloc(1, 20);
+ sprintf(success_new->value, "%i", control->data.image.mx);
+ success_new->next = 0;
+ last_success->next = success_new;
+ last_success = success_new;
+ /* y */
+ success_new = xcalloc(1, sizeof(*success_new));
+ success_new->name = xcalloc(1, len);
+ sprintf(success_new->name, "%s.y", control->name);
+ success_new->value = xcalloc(1, 20);
+ sprintf(success_new->value, "%i", control->data.image.my);
+ success_new->next = 0;
+ last_success->next = success_new;
+ last_success = success_new;
+ }
+
+ /* ignore reset */
+ if (control->type == GADGET_RESET)
+ continue;
+
+ /* all others added if they have a value */
+ if (control->value) {
+ success_new = xcalloc(1, sizeof(*success_new));
+ success_new->name = xstrdup(control->name);
+ success_new->value = xstrdup(control->value);
+ success_new->next = 0;
+ last_success->next = success_new;
+ last_success = success_new;
+ }
+ }
+
+ return sentinel.next;
+}
+
+
+/**
+ * Encode controls using application/x-www-form-urlencoded.
+ */
+
+char *form_url_encode(struct form_successful_control *control)
+{
+ char *s = xcalloc(1, 0);
+ int len = 0, len1;
+
+ for (; control; control = control->next) {
+ char *name = curl_escape(control->name, 0);
+ char *value = curl_escape(control->value, 0);
+ len1 = len + strlen(name) + strlen(value) + 2;
+ s = xrealloc(s, len1 + 1);
+ sprintf(s + len, "%s=%s&", name, value);
+ len = len1;
+ curl_free(name);
+ curl_free(value);
+ }
+ if (len)
+ s[len - 1] = 0;
+ return s;
+}
+
+
+/**
+ * Free a linked list of form_successful_control.
+ */
+
+void form_free_successful(struct form_successful_control *control)
+{
+ struct form_successful_control *next;
+ for (; control; control = next) {
+ next = control->next;
+ free(control->name);
+ free(control->value);
+ free(control);
+ }
+}
diff --git a/render/form.h b/render/form.h
new file mode 100644
index 000000000..b81abf01a
--- /dev/null
+++ b/render/form.h
@@ -0,0 +1,89 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
+ * Copyright 2003 James Bursa <bursa@users.sourceforge.net>
+ */
+
+/** \file
+ * Form handling functions (interface).
+ */
+
+#ifndef _NETSURF_RENDER_FORM_H_
+#define _NETSURF_RENDER_FORM_H_
+
+#include <stdbool.h>
+#include "netsurf/render/box.h"
+
+struct form_control;
+struct form_option;
+
+/** HTML form. */
+struct form {
+ char *action; /* url */
+ enum {method_GET, method_POST} method;
+ struct form_control *controls; /**< Linked list of controls. */
+ struct form_control *last_control; /**< Last control in list. */
+};
+
+/** Form control. */
+struct form_control {
+ enum { GADGET_HIDDEN, GADGET_TEXTBOX, GADGET_RADIO, GADGET_CHECKBOX,
+ GADGET_SELECT, GADGET_TEXTAREA, GADGET_IMAGE,
+ GADGET_PASSWORD, GADGET_SUBMIT, GADGET_RESET } type;
+ char *name;
+ char *value;
+ char *initial_value;
+ bool disabled;
+ struct form *form;
+ struct box *box;
+ struct box *caret_inline_container;
+ struct box *caret_text_box;
+ int caret_char_offset;
+ unsigned int maxlength;
+ union {
+ struct {
+ int mx, my;
+ } image;
+ struct {
+ int num_items;
+ struct form_option *items, *last_item;
+ bool multiple;
+ int num_selected;
+ /** Currently selected item, if num_selected == 1. */
+ struct form_option *current;
+ } select;
+ struct {
+ int selected;
+ } checkbox;
+ struct {
+ int selected;
+ } radio;
+ } data;
+ struct form_control *next; /**< Next control in this form. */
+};
+
+/** Option in a select. */
+struct form_option {
+ bool selected;
+ bool initial_selected;
+ char* value;
+ char* text;
+ struct form_option* next;
+};
+
+/** Successful control, as defined by HTML 4.01 17.13. */
+struct form_successful_control {
+ char *name; /**< Control name. */
+ char *value; /**< Current value. */
+ struct form_successful_control *next; /**< Next in linked list. */
+};
+
+void form_add_control(struct form *form, struct form_control *control);
+struct form_successful_control *form_successful_controls(struct form *form,
+ struct form_control *submit_button);
+char *form_url_encode(struct form_successful_control *control);
+void form_free_successful(struct form_successful_control *control);
+
+#endif