From bf1e787deb2aceeeebf810150c368f3d906db1ef648a336751e54a2ca5c0483d Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Fri, 1 Aug 2025 02:08:15 -0400 Subject: [PATCH] Forms code is a bit more RAII. --- src/form.cc | 122 ++++++++++++++++++--------------------------- src/form.hh | 42 ++++++++++++++-- src/html.cc | 12 ++--- src/html_common.hh | 2 +- 4 files changed, 92 insertions(+), 86 deletions(-) diff --git a/src/form.cc b/src/form.cc index 8524300..dfeac39 100644 --- a/src/form.cc +++ b/src/form.cc @@ -57,35 +57,11 @@ static Embed *Html_input_image(DilloHtml *html, const char *tag, int tagsize); static void Html_option_finish(DilloHtml *html); -/* - * Typedefs - */ - -typedef enum { - DILLO_HTML_INPUT_UNKNOWN, - DILLO_HTML_INPUT_TEXT, - DILLO_HTML_INPUT_PASSWORD, - DILLO_HTML_INPUT_CHECKBOX, - DILLO_HTML_INPUT_RADIO, - DILLO_HTML_INPUT_IMAGE, - DILLO_HTML_INPUT_FILE, - DILLO_HTML_INPUT_BUTTON, - DILLO_HTML_INPUT_HIDDEN, - DILLO_HTML_INPUT_SUBMIT, - DILLO_HTML_INPUT_RESET, - DILLO_HTML_INPUT_BUTTON_SUBMIT, - DILLO_HTML_INPUT_BUTTON_RESET, - DILLO_HTML_INPUT_SELECT, - DILLO_HTML_INPUT_SEL_LIST, - DILLO_HTML_INPUT_TEXTAREA, - DILLO_HTML_INPUT_INDEX -} DilloHtmlInputType; - /* * Class declarations */ -class DilloHtmlForm { +class DilloHtmlFormImpl : public DilloHtmlForm { friend class DilloHtmlReceiver; friend class DilloHtmlInput; @@ -111,28 +87,33 @@ class DilloHtmlForm { public: //BUG: for now everything is public DilloHtmlMethod method; + DilloHtmlMethod get_method() const override { return method; } + DilloUrl *action; DilloHtmlEnc content_type; + DilloHtmlEnc get_content_type() const override { return content_type; } char *submit_charset; std::vector< std::shared_ptr< DilloHtmlInput > > inputs; + std::vector< std::shared_ptr< DilloHtmlInput > > *get_inputs() override { return &inputs; } + int num_entry_fields; std::unique_ptr< DilloHtmlReceiver > form_receiver; public: - DilloHtmlForm (DilloHtml *html, + DilloHtmlFormImpl (DilloHtml *html, DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc content_type, const char *charset, bool enabled); - ~DilloHtmlForm (); + ~DilloHtmlFormImpl () override; std::shared_ptr< DilloHtmlInput > getInput (Resource *resource); std::shared_ptr< DilloHtmlInput > getRadioInput (const char *name); void submit(DilloHtmlInput *active_input, EventButton *event); void reset (); void display_hiddens(bool display); - void addInput(std::unique_ptr< DilloHtmlInput > input, DilloHtmlInputType type); + void addInput(std::unique_ptr< DilloHtmlInput > input, DilloHtmlInputType type) override; void setEnabled(bool enabled); }; @@ -141,11 +122,11 @@ class DilloHtmlReceiver: public Resource::ClickedReceiver { private: - friend class DilloHtmlForm; - DilloHtmlForm* form; + friend class DilloHtmlFormImpl; + DilloHtmlFormImpl* form; public: - DilloHtmlReceiver (DilloHtmlForm* form2) { form = form2; } + DilloHtmlReceiver (DilloHtmlFormImpl* form2) { form = form2; } ~DilloHtmlReceiver () { } private: @@ -157,8 +138,8 @@ private: class DilloHtmlInput { - // DilloHtmlForm::addInput() calls connectTo() - friend class DilloHtmlForm; + // DilloHtmlFormImpl::addInput() calls connectTo() + friend class DilloHtmlFormImpl; public: //BUG: for now everything is public DilloHtmlInputType type; @@ -174,7 +155,7 @@ public: //BUG: for now everything is public private: void connectTo(DilloHtmlReceiver *form_receiver); - void activate(DilloHtmlForm *form, int num_entry_fields,EventButton *event); + void activate(DilloHtmlFormImpl *form, int num_entry_fields,EventButton *event); void readFile(BrowserWindow *bw); public: @@ -250,20 +231,15 @@ public: * Form API */ -DilloHtmlForm *a_Html_form_new (DilloHtml *html, DilloHtmlMethod method, +std::unique_ptr< DilloHtmlForm > a_Html_form_new (DilloHtml *html, DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc content_type, const char *charset, bool enabled) { - return new DilloHtmlForm (html, method, action, content_type, charset, + return std::make_unique< DilloHtmlFormImpl > (html, method, action, content_type, charset, enabled); } -void a_Html_form_delete (DilloHtmlForm *form) -{ - delete form; -} - void a_Html_input_delete (DilloHtmlInput *input) { delete input; @@ -271,17 +247,17 @@ void a_Html_input_delete (DilloHtmlInput *input) void a_Html_form_submit2(void *vform) { - ((DilloHtmlForm *)vform)->submit(NULL, NULL); + ((DilloHtmlFormImpl *)vform)->submit(NULL, NULL); } void a_Html_form_reset2(void *vform) { - ((DilloHtmlForm *)vform)->reset(); + ((DilloHtmlFormImpl *)vform)->reset(); } void a_Html_form_display_hiddens2(void *vform, bool display) { - ((DilloHtmlForm *)vform)->display_hiddens(display); + ((DilloHtmlFormImpl *)vform)->display_hiddens(display); } /* @@ -318,7 +294,7 @@ static std::shared_ptr< DilloHtmlInput > Html_get_radio_input(DilloHtml *html, c std::vector< std::shared_ptr< DilloHtmlInput > > *inputs; if (html->InFlags & IN_FORM) - inputs = &html->getCurrentForm()->inputs; + inputs = html->getCurrentForm()->get_inputs(); else inputs = &html->inputs_outside_form; @@ -340,7 +316,7 @@ static std::shared_ptr< DilloHtmlInput > Html_get_current_input(DilloHtml &html) std::vector< std::shared_ptr< DilloHtmlInput > > *inputs; if (html.InFlags & IN_FORM) - inputs = &html.getCurrentForm()->inputs; + inputs = html.getCurrentForm()->get_inputs(); else inputs = &html.inputs_outside_form; @@ -524,11 +500,11 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize) bool valid = true; if (html->InFlags & IN_FORM) { DilloHtmlForm *form = html->getCurrentForm(); - if (form->method != DILLO_HTML_METHOD_POST) { + if (form->get_method() != DILLO_HTML_METHOD_POST) { valid = false; BUG_MSG("
with file input MUST use HTTP POST method."); MSG("File input ignored in form not using HTTP POST method\n"); - } else if (form->content_type != DILLO_HTML_ENC_MULTIPART) { + } else if (form->get_content_type() != DILLO_HTML_ENC_MULTIPART) { valid = false; BUG_MSG(" with file input MUST use multipart/form-data" " encoding."); @@ -988,7 +964,7 @@ void Html_tag_close_button(DilloHtml *html) /* * Constructor */ -DilloHtmlForm::DilloHtmlForm (DilloHtml *html2, +DilloHtmlFormImpl::DilloHtmlFormImpl (DilloHtml *html2, DilloHtmlMethod method2, const DilloUrl *action2, DilloHtmlEnc content_type2, @@ -1008,16 +984,16 @@ DilloHtmlForm::DilloHtmlForm (DilloHtml *html2, /* * Destructor */ -DilloHtmlForm::~DilloHtmlForm () +DilloHtmlFormImpl::~DilloHtmlFormImpl () { delete action; dFree(submit_charset); inputs.clear(); } -void DilloHtmlForm::eventHandler(Resource *resource, EventButton *event) +void DilloHtmlFormImpl::eventHandler(Resource *resource, EventButton *event) { - _MSG("DilloHtmlForm::eventHandler\n"); + _MSG("DilloHtmlFormImpl::eventHandler\n"); if (event && (event->button == 3)) { a_UIcmd_form_popup(html->bw, html->page_url, this, showing_hiddens); } else { @@ -1025,7 +1001,7 @@ void DilloHtmlForm::eventHandler(Resource *resource, EventButton *event) if (input) { input->activate (this, num_entry_fields, event); } else { - MSG("DilloHtmlForm::eventHandler: ERROR, input not found!\n"); + MSG("DilloHtmlFormImpl::eventHandler: ERROR, input not found!\n"); } } } @@ -1034,7 +1010,7 @@ void DilloHtmlForm::eventHandler(Resource *resource, EventButton *event) * Submit. * (Called by eventHandler()) */ -void DilloHtmlForm::submit(DilloHtmlInput *active_input, EventButton *event) +void DilloHtmlFormImpl::submit(DilloHtmlInput *active_input, EventButton *event) { if (!dStrAsciiCasecmp(URL_SCHEME(html->page_url), "https") && dStrAsciiCasecmp(URL_SCHEME(action), "https")) { @@ -1066,7 +1042,7 @@ void DilloHtmlForm::submit(DilloHtmlInput *active_input, EventButton *event) * Build a new query URL. * (Called by submit()) */ -std::unique_ptr< DilloUrl > DilloHtmlForm::buildQueryUrl(DilloHtmlInput *active_input) +std::unique_ptr< DilloUrl > DilloHtmlFormImpl::buildQueryUrl(DilloHtmlInput *active_input) { std::unique_ptr< DilloUrl > new_url; @@ -1075,7 +1051,7 @@ std::unique_ptr< DilloUrl > DilloHtmlForm::buildQueryUrl(DilloHtmlInput *active_ std::string DataStr; DilloHtmlInput *active_submit = NULL; - _MSG("DilloHtmlForm::buildQueryUrl: action=%s\n",URL_STR_(action)); + _MSG("DilloHtmlFormImpl::buildQueryUrl: action=%s\n",URL_STR_(action)); if (active_input) { if ((active_input->type == DILLO_HTML_INPUT_SUBMIT) || @@ -1114,7 +1090,7 @@ std::unique_ptr< DilloUrl > DilloHtmlForm::buildQueryUrl(DilloHtmlInput *active_ dFree(action_str); } } else { - MSG("DilloHtmlForm::buildQueryUrl: Method unknown\n"); + MSG("DilloHtmlFormImpl::buildQueryUrl: Method unknown\n"); } return new_url; @@ -1123,7 +1099,7 @@ std::unique_ptr< DilloUrl > DilloHtmlForm::buildQueryUrl(DilloHtmlInput *active_ /** * Construct the data for a query URL */ -std::optional< std::string > DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit) +std::optional< std::string > DilloHtmlFormImpl::buildQueryData(DilloHtmlInput *active_submit) { std::string DataStr; char *boundary = nullptr; @@ -1256,7 +1232,7 @@ static void generate_boundary(Dstr *boundary) * Generate a boundary string for use in separating the parts of a * multipart/form-data submission. */ -char *DilloHtmlForm::makeMultipartBoundary(iconv_t char_encoder, +char *DilloHtmlFormImpl::makeMultipartBoundary(iconv_t char_encoder, DilloHtmlInput *active_submit) { std::vector< std::string > values; @@ -1307,7 +1283,7 @@ char *DilloHtmlForm::makeMultipartBoundary(iconv_t char_encoder, * Return value: same input Dstr if no encoding is needed. * new Dstr when encoding (input Dstr is freed). */ -std::string DilloHtmlForm::encodeText(iconv_t char_encoder, std::string &&input) +std::string DilloHtmlFormImpl::encodeText(iconv_t char_encoder, std::string &&input) { int rc = 0; Dstr *output; @@ -1375,7 +1351,7 @@ std::string DilloHtmlForm::encodeText(iconv_t char_encoder, std::string &&input) /** * Urlencode 'str' and append it to 'dstr' */ -void DilloHtmlForm::strUrlencodeAppend(std::string &dstr, std::string_view str_) +void DilloHtmlFormImpl::strUrlencodeAppend(std::string &dstr, std::string_view str_) { const std::string str{ str_ }; auto encoded= Alepha::AutoRAII @@ -1389,7 +1365,7 @@ void DilloHtmlForm::strUrlencodeAppend(std::string &dstr, std::string_view str_) /** * Append a name-value pair to url data using url encoding. */ -void DilloHtmlForm::inputUrlencodeAppend(std::string &data, const std::string_view name, +void DilloHtmlFormImpl::inputUrlencodeAppend(std::string &data, const std::string_view name, const std::string_view value) { if (not name.empty()) { @@ -1404,7 +1380,7 @@ void DilloHtmlForm::inputUrlencodeAppend(std::string &data, const std::string_vi * Append files to URL data using multipart encoding. * Currently only accepts one file. */ -void DilloHtmlForm::filesInputMultipartAppend(std::string &data, +void DilloHtmlFormImpl::filesInputMultipartAppend(std::string &data, std::string_view boundary, std::string_view name, const std::string &file, @@ -1453,7 +1429,7 @@ void DilloHtmlForm::filesInputMultipartAppend(std::string &data, /** * Append a name-value pair to url data using multipart encoding. */ -void DilloHtmlForm::inputMultipartAppend(std::string &data, +void DilloHtmlFormImpl::inputMultipartAppend(std::string &data, std::string_view boundary, std::string_view name, std::string_view value) @@ -1476,7 +1452,7 @@ void DilloHtmlForm::inputMultipartAppend(std::string &data, /** * Append an image button click position to url data using url encoding. */ -void DilloHtmlForm::imageInputUrlencodeAppend(std::string &data, const std::string_view name, const std::string_view x, +void DilloHtmlFormImpl::imageInputUrlencodeAppend(std::string &data, const std::string_view name, const std::string_view x, const std::string_view y) { if (not name.empty()) { @@ -1495,7 +1471,7 @@ void DilloHtmlForm::imageInputUrlencodeAppend(std::string &data, const std::stri /** * Append an image button click position to url data using multipart encoding. */ -void DilloHtmlForm::imageInputMultipartAppend(std::string &data, const std::string_view boundary, +void DilloHtmlFormImpl::imageInputMultipartAppend(std::string &data, const std::string_view boundary, const std::string_view name_, const std::string_view x_, const std::string_view y_) { std::string name{ name_ }; @@ -1517,7 +1493,7 @@ void DilloHtmlForm::imageInputMultipartAppend(std::string &data, const std::stri * Reset all inputs containing reset to their initial values. In * general, reset is the reset button for the form. */ -void DilloHtmlForm::reset () +void DilloHtmlFormImpl::reset () { int size = inputs.size(); for (int i = 0; i < size; i++) @@ -1527,7 +1503,7 @@ void DilloHtmlForm::reset () /** * Show/hide "hidden" form controls */ -void DilloHtmlForm::display_hiddens(bool display) +void DilloHtmlFormImpl::display_hiddens(bool display) { int size = inputs.size(); for (int i = 0; i < size; i++) { @@ -1539,7 +1515,7 @@ void DilloHtmlForm::display_hiddens(bool display) showing_hiddens = display; } -void DilloHtmlForm::setEnabled(bool enabled) +void DilloHtmlFormImpl::setEnabled(bool enabled) { for (int i = 0; i < inputs.size(); i++) inputs.at(i)->setEnabled(enabled); @@ -1548,7 +1524,7 @@ void DilloHtmlForm::setEnabled(bool enabled) /** * Add a new input. */ -void DilloHtmlForm::addInput(std::unique_ptr< DilloHtmlInput > input, DilloHtmlInputType type) +void DilloHtmlFormImpl::addInput(std::unique_ptr< DilloHtmlInput > input, DilloHtmlInputType type) { input->connectTo (form_receiver.get()); input->setEnabled (enabled); @@ -1564,7 +1540,7 @@ void DilloHtmlForm::addInput(std::unique_ptr< DilloHtmlInput > input, DilloHtmlI /** * Return the input with a given resource. */ -std::shared_ptr< DilloHtmlInput > DilloHtmlForm::getInput (Resource *resource) +std::shared_ptr< DilloHtmlInput > DilloHtmlFormImpl::getInput (Resource *resource) { for (int idx = 0; idx < inputs.size(); idx++) { auto input = inputs.at(idx); @@ -1578,7 +1554,7 @@ std::shared_ptr< DilloHtmlInput > DilloHtmlForm::getInput (Resource *resource) /** * Return a Radio input for the given name. */ -std::shared_ptr< DilloHtmlInput > DilloHtmlForm::getRadioInput (const char *name) +std::shared_ptr< DilloHtmlInput > DilloHtmlFormImpl::getRadioInput (const char *name) { for (int idx = 0; idx < inputs.size(); idx++) { auto input = inputs.at(idx); @@ -1703,7 +1679,7 @@ void DilloHtmlInput::connectTo(DilloHtmlReceiver *form_receiver) /** * Activate a form */ -void DilloHtmlInput::activate(DilloHtmlForm *form, int num_entry_fields, +void DilloHtmlInput::activate(DilloHtmlFormImpl *form, int num_entry_fields, EventButton *event) { switch (type) { diff --git a/src/form.hh b/src/form.hh index 13ca79f..e13102c 100644 --- a/src/form.hh +++ b/src/form.hh @@ -1,6 +1,9 @@ #ifndef __FORM_HH__ #define __FORM_HH__ +#include +#include + #include "url.hh" /* @@ -18,25 +21,56 @@ typedef enum { DILLO_HTML_ENC_MULTIPART } DilloHtmlEnc; +enum DilloHtmlInputType { + DILLO_HTML_INPUT_UNKNOWN, + DILLO_HTML_INPUT_TEXT, + DILLO_HTML_INPUT_PASSWORD, + DILLO_HTML_INPUT_CHECKBOX, + DILLO_HTML_INPUT_RADIO, + DILLO_HTML_INPUT_IMAGE, + DILLO_HTML_INPUT_FILE, + DILLO_HTML_INPUT_BUTTON, + DILLO_HTML_INPUT_HIDDEN, + DILLO_HTML_INPUT_SUBMIT, + DILLO_HTML_INPUT_RESET, + DILLO_HTML_INPUT_BUTTON_SUBMIT, + DILLO_HTML_INPUT_BUTTON_RESET, + DILLO_HTML_INPUT_SELECT, + DILLO_HTML_INPUT_SEL_LIST, + DILLO_HTML_INPUT_TEXTAREA, + DILLO_HTML_INPUT_INDEX +}; + /* * Classes */ - -class DilloHtmlForm; class DilloHtmlInput; class DilloHtml; +class DilloHtmlForm +{ + public: + virtual ~DilloHtmlForm()= default; + + virtual void addInput(std::unique_ptr< DilloHtmlInput > input, DilloHtmlInputType type)= 0; + + virtual std::vector< std::shared_ptr< DilloHtmlInput > > *get_inputs()= 0; + + virtual DilloHtmlMethod get_method() const= 0; + virtual DilloHtmlEnc get_content_type() const= 0; +}; + + /* * Form API */ -DilloHtmlForm *a_Html_form_new(DilloHtml *html, +std::unique_ptr< DilloHtmlForm > a_Html_form_new(DilloHtml *html, DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc enc, const char *charset, bool enabled); -void a_Html_form_delete(DilloHtmlForm* form); void a_Html_input_delete(DilloHtmlInput* input); void a_Html_form_submit2(void *v_form); void a_Html_form_reset2(void *v_form); diff --git a/src/html.cc b/src/html.cc index 8554e6c..9a7f0a4 100644 --- a/src/html.cc +++ b/src/html.cc @@ -252,7 +252,7 @@ void a_Html_load_images(void *v_html, DilloUrl *pattern) static bool Html_contains_form(DilloHtml *html, void *v_form) { for (std::size_t i = 0; i < html->forms.size(); i++) { - if (html->forms.at(i) == v_form) { + if (html->forms.at(i).get() == v_form) { return true; } } @@ -552,10 +552,6 @@ DilloHtml::~DilloHtml() delete page_url; delete base_url; - for (std::size_t i = 0; i < forms.size(); i++) - a_Html_form_delete (forms.at(i)); - forms.clear(); - for (int i = 0; i < images->size(); i++) { DilloHtmlImage *img = images->get(i); delete img->url; @@ -661,11 +657,11 @@ int DilloHtml::formNew(DilloHtmlMethod method, const DilloUrl *action, { // avoid data loss on repush after CSS stylesheets have been loaded bool enabled = bw->NumPendingStyleSheets == 0; - DilloHtmlForm *form = a_Html_form_new (this, method, action, + auto form = a_Html_form_new (this, method, action, enc, charset, enabled); int nf = forms.size (); (void) nf; - forms.emplace_back (form); + forms.push_back (std::move( form )); _MSG("Html formNew: action=%s nform=%d\n", action, nf); return forms.size(); } @@ -675,7 +671,7 @@ int DilloHtml::formNew(DilloHtmlMethod method, const DilloUrl *action, */ DilloHtmlForm *DilloHtml::getCurrentForm () { - return forms.back(); + return forms.back().get(); } bool_t DilloHtml::unloadedImages() diff --git a/src/html_common.hh b/src/html_common.hh index 59e9f7e..d375201 100644 --- a/src/html_common.hh +++ b/src/html_common.hh @@ -219,7 +219,7 @@ public: //BUG: for now everything is public /* -------------------------------------------------------------------*/ /* Variables required after parsing (for page functionality) */ /* -------------------------------------------------------------------*/ - std::vector< DilloHtmlForm * > forms; + std::vector< std::unique_ptr< DilloHtmlForm > > forms; std::vector< std::shared_ptr< DilloHtmlInput > > inputs_outside_form; std::vector< std::unique_ptr< DilloUrl > > links; lout::misc::SimpleVector *images;