1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-11-04 08:17:17 -05:00

[mujs] Code rewritten to C

Likely some bugs were introduced here.
elinks with mujs suppport can be built by tcc.
This commit is contained in:
Witold Filipczyk 2023-12-30 21:42:31 +01:00
parent 8b5cb79485
commit 4c7364c14e
7 changed files with 558 additions and 432 deletions

View File

@ -87,24 +87,6 @@ mujs_init(struct module *xxx)
static void
mujs_done(struct module *xxx)
{
attr_clear_map(map_attrs);
attr_clear_map(map_attributes);
attr_clear_map(map_rev_attributes);
attr_clear_map(map_collections);
attr_clear_map(map_rev_collections);
attr_clear_map(map_doctypes);
attr_clear_map(map_elements);
attr_clear_map(map_privates);
attr_clear_map(map_form_elements);
attr_clear_map(map_elements_form);
attr_clear_map(map_form);
attr_clear_map(map_rev_form);
attr_clear_map(map_forms);
attr_clear_map(map_rev_forms);
attr_clear_map(map_inputs);
attr_clear_map(map_nodelist);
attr_clear_map(map_rev_nodelist);
attr_delete_map(map_attrs);
attr_delete_map(map_attributes);
attr_delete_map(map_rev_attributes);

View File

@ -2,6 +2,6 @@ top_builddir=../../..
include $(top_builddir)/Makefile.config
OBJS = attr.o attributes.o collection.o console.o document.o element.o form.o forms.o history.o implementation.o input.o \
keyboard.o localstorage.o location.o mapa.obj message.o navigator.o nodelist.o screen.o style.o unibar.o window.o xhr.o
keyboard.o localstorage.o location.o mapa.o message.o navigator.o nodelist.o screen.o style.o unibar.o window.o xhr.o
include $(top_srcdir)/Makefile.lib

550
src/ecmascript/mujs/mapa.c Normal file
View File

@ -0,0 +1,550 @@
/* map temporary file */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "elinks.h"
#include <stdbool.h>
#include <stdlib.h>
#include "ecmascript/mujs.h"
#include "ecmascript/mujs/mapa.h"
#include "ecmascript/mujs/xhr.h"
#include "util/hash.h"
#include "util/memory.h"
#include "util/string.h"
void
attr_save_in_map(void *m, void *node, void *value)
{
struct hash *hash = (struct hash *)m;
if (hash) {
char *key = memacpy((const char *)&node, sizeof(node));
if (key) {
add_hash_item(hash, key, sizeof(node), value);
}
}
}
void *
attr_create_new_map(void)
{
return (void *)init_hash8();
}
void *
attr_create_new_attrs_map(void)
{
return (void *)init_hash8();
}
#if 0
struct classcomp {
bool operator() (const std::string& lhs, const std::string& rhs) const
{
return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
}
};
#endif
void *
attr_create_new_requestHeaders_map(void)
{
return (void *)init_hash8();
}
void *
attr_create_new_responseHeaders_map(void)
{
return (void *)init_hash8();
}
void
delete_map_str(void *m)
{
struct hash *hash = (struct hash *)m;
if (hash) {
struct hash_item *item;
int i;
foreach_hash_item (item, *hash, i) {
mem_free_set(&item->key, NULL);
mem_free_set(&item->value, NULL);
}
free_hash(&hash);
}
}
void
attr_delete_map(void *m)
{
struct hash *hash = (struct hash *)m;
if (hash) {
struct hash_item *item;
int i;
foreach_hash_item (item, *hash, i) {
mem_free_set(&item->key, NULL);
}
free_hash(&hash);
}
}
void *
attr_find_in_map(void *m, void *node)
{
struct hash *hash = (struct hash *)m;
if (hash) {
char *key = memacpy((const char *)&node, sizeof(node));
if (key) {
struct hash_item *item = get_hash_item(hash, key, sizeof(node));
mem_free(key);
if (item) {
return item->value;
}
}
}
return NULL;
}
void
attr_erase_from_map(void *m, void *node)
{
struct hash *hash = (struct hash *)m;
if (hash) {
char *key = memacpy((const char *)&node, sizeof(node));
if (key) {
struct hash_item *item = get_hash_item(hash, key, sizeof(node));
if (item) {
mem_free_set(&item->key, NULL);
del_hash_item(hash, item);
}
mem_free(key);
}
}
}
static int
explode(char *s, const char c, char **header, char **value)
{
char *next;
char *colon = strchr(s, c);
if (!colon) {
return 0;
}
*header = memacpy(s, colon - s);
next = colon + 1;
colon = strchr(next, c);
if (colon) {
return 1;
}
*value = stracpy(next);
return 2;
}
//static std::map<std::string, std::string> *
static void *
get_requestHeaders(void *h)
{
return h;
}
//static std::map<std::string, std::string, classcomp> *
static void *
get_responseHeaders(void *h)
{
return h;
}
void
process_xhr_headers(char *head, struct mjs_xhr *x)
{
char *next, *next2, *line;
char *headers = stracpy(head);
char *space;
char *statusText;
char *newline;
char *stat;
int status;
if (!headers) {
return;
}
newline = strchr(headers, '\n');
if (newline) {
*newline = '\0';
}
space = strchr(headers, ' ');
if (!space) {
return;
}
stat = space + 1;
space = strchr(stat, ' ');
if (space) {
*space = '\0';
statusText = space + 1;
} else {
statusText = NULL;
}
status = atoi(stat);
struct hash *responseHeaders = get_responseHeaders(x->responseHeaders);
struct hash_item *item;
if (newline) {
next = newline + 1;
next2 = strchr(next, '\n');
} else {
next = next2 = NULL;
}
while (1) {
char *value = NULL;
char *header = NULL;
int size;
if (!next) {
break;
}
line = next;
if (!next2) {
next = NULL;
} else {
next = next2 + 1;
next2 = strchr(next, '\n');
}
next = next2 + 1;
size = explode(line, ':', &header, &value);
if (size == 0) {
continue;
}
if (size == 1 || !value) {
mem_free_set(&header, NULL);
continue;
}
if (!header) {
mem_free(value);
continue;
}
char *normalized_value = normalize(value);
item = get_hash_item(responseHeaders, header, strlen(header));
if (item) {
struct string hh;
if (init_string(&hh)) {
add_to_string(&hh, (char *)item->value);
add_to_string(&hh, ", ");
add_to_string(&hh, normalized_value);
mem_free_set(&item->value, hh.source);
}
} else {
add_hash_item(responseHeaders, header, strlen(header), stracpy(normalized_value));
}
mem_free(header);
mem_free(value);
}
x->status = status;
mem_free_set(&x->statusText, null_or_stracpy(statusText));
}
void
set_xhr_header(char *normalized_value, const char *h_name, struct mjs_xhr *x)
{
struct hash *requestHeaders = get_requestHeaders(x->requestHeaders);
struct hash_item *item;
char *key;
if (!requestHeaders || !h_name) {
return;
}
item = get_hash_item(requestHeaders, h_name, strlen(h_name));
if (item) {
struct string hh;
if (init_string(&hh)) {
add_to_string(&hh, item->value);
add_to_string(&hh, ", ");
add_to_string(&hh, normalized_value);
mem_free_set(&item->value, hh.source);
}
return;
}
key = stracpy(h_name);
if (key) {
add_hash_item(requestHeaders, key, strlen(key), stracpy(normalized_value));
}
}
char *
get_output_headers(struct mjs_xhr *x)
{
struct string output;
struct hash *hash = (struct hash *)get_responseHeaders(x->responseHeaders);;
struct hash_item *item;
int i;
if (!hash || !init_string(&output)) {
return NULL;
}
foreach_hash_item (item, *hash, i) {
add_to_string(&output, item->key);
add_to_string(&output, ": ");
add_to_string(&output, item->value);
add_to_string(&output, "\r\n");
}
return output.source;
}
char *
get_output_header(const char *header_name, struct mjs_xhr *x)
{
struct hash *hash = get_responseHeaders(x->responseHeaders);
struct hash_item *item;
if (!hash || !header_name) {
return NULL;
}
item = get_hash_item(hash, header_name, strlen(header_name));
if (!item) {
return NULL;
}
return null_or_stracpy(item->value);
}
const char *good[] = { "background",
"background-color",
"color",
"display",
"font-style",
"font-weight",
"list-style",
"list-style-type",
"text-align",
"text-decoration",
"white-space",
NULL
};
bool
isGood(const char *param)
{
int i;
for (i = 0; good[i]; i++) {
if (!strcmp(param, good[i])) {
return true;
}
}
return false;
}
#if 0
static std::string
trimString(std::string str)
{
const std::string whiteSpaces = " \t\n\r\f\v";
// Remove leading whitespace
size_t first_non_space = str.find_first_not_of(whiteSpaces);
str.erase(0, first_non_space);
// Remove trailing whitespace
size_t last_non_space = str.find_last_not_of(whiteSpaces);
str.erase(last_non_space + 1);
return str;
}
#endif
char *
trimString(char *str)
{
char *whitespace = " \t\n\r\f\v";
char *end = strchr(str, '\0') - 1;
str += strspn(str, whitespace);
while (end > str) {
char *s;
int bad = 0;
for (s = whitespace; *s; s++) {
if (*end == *s) {
bad = 1;
*end = '\0';
break;
}
}
if (!bad) {
break;
}
end--;
}
return str;
}
void *
set_elstyle(const char *text)
{
char *str, *param, *value, *next, *next2;
struct hash *css = NULL;
if (!text || !*text) {
return NULL;
}
str = stracpy(text);
next = str;
while (next) {
char *semicolon = strchr(str, ';');
char *colon;
char *params;
if (semicolon) {
*semicolon = '\0';
next2 = semicolon + 1;
} else {
next2 = NULL;
}
params = next;
colon = strchr(params, ':');
if (!colon) {
goto next_iter;
}
*colon = '\0';
param = trimString(params);
params = colon + 1;
colon = strchr(params, ':');
if (colon) {
*colon = '\0';
}
value = trimString(params);
if (isGood(param)) {
if (!css) {
css = init_hash8();
}
if (css) {
char *key = stracpy(param);
if (key) {
add_hash_item(css, key, strlen(key), stracpy(value));
}
}
}
next_iter:
next = next2;
}
return (void *)css;
}
char *
get_elstyle(void *m)
{
struct hash *css = (struct hash *)m;
char *delimiter = "";
struct hash_item *item;
struct string output;
int i;
if (!init_string(&output)) {
delete_map_str(css);
return NULL;
}
foreach_hash_item (item, *css, i) {
add_to_string(&output, delimiter);
add_to_string(&output, item->key);
add_char_to_string(&output, ':');
add_to_string(&output, item->value);
delimiter = ";";
}
delete_map_str(css);
return output.source;
}
char *
get_css_value(const char *text, const char *param)
{
void *m = set_elstyle(text);
char *res = NULL;
struct hash *css;
struct hash_item *item;
if (!m) {
return stracpy("");
}
css = (struct hash *)m;
item = get_hash_item(css, param, strlen(param));
if (item) {
res = stracpy(item->value);
} else {
res = stracpy("");
}
delete_map_str(css);
return res;
}
char *
set_css_value(const char *text, const char *param, const char *value)
{
void *m = set_elstyle(text);
if (m) {
if (isGood(param)) {
struct hash *hash = (struct hash *)m;
char *key = stracpy(param);
if (key) {
add_hash_item(hash, key, strlen(key), stracpy(value));
}
}
return get_elstyle(m);
}
if (isGood(param)) {
struct hash *css = init_hash8();
char *key;
if (!css) {
return stracpy("");
}
key = stracpy(param);
if (key) {
add_hash_item(css, key, strlen(key), stracpy(value));
}
return get_elstyle((void *)css);
}
return stracpy("");
}

View File

@ -1,405 +0,0 @@
/* map temporary file */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "elinks.h"
#include "ecmascript/mujs.h"
#include "ecmascript/mujs/mapa.h"
#include "ecmascript/mujs/xhr.h"
#include "util/memory.h"
#include "util/string.h"
#include <cstddef>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
void
attr_save_in_map(void *m, void *node, void *value)
{
std::map<void *, void *> *mapa = static_cast<std::map<void *, void *> *>(m);
(*mapa)[node] = value;
}
void *
attr_create_new_map(void)
{
std::map<void *, void *> *mapa = new std::map<void *, void *>;
return (void *)mapa;
}
void *
attr_create_new_attrs_map(void)
{
std::map<void *, void *> *mapa = new std::map<void *, void *>;
return (void *)mapa;
}
struct classcomp {
bool operator() (const std::string& lhs, const std::string& rhs) const
{
return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
}
};
void *
attr_create_new_requestHeaders_map(void)
{
std::map<std::string, std::string> *mapa = new std::map<std::string, std::string>;
return (void *)mapa;
}
void *
attr_create_new_responseHeaders_map(void)
{
std::map<std::string, std::string, classcomp> *mapa = new std::map<std::string, std::string, classcomp>;
return (void *)mapa;
}
void
attr_clear_map(void *m)
{
std::map<void *, void *> *mapa = static_cast<std::map<void *, void *> *>(m);
mapa->clear();
}
void
delete_map_str(void *m)
{
std::map<std::string, std::string> *mapa = static_cast<std::map<std::string, std::string> *>(m);
if (mapa) {
delete(mapa);
}
}
void
attr_delete_map(void *m)
{
std::map<void *, void *> *mapa = static_cast<std::map<void *, void *> *>(m);
if (mapa) {
delete(mapa);
}
}
void *
attr_find_in_map(void *m, void *node)
{
std::map<void *, void *> *mapa = static_cast<std::map<void *, void *> *>(m);
if (!mapa) {
return NULL;
}
auto value = (*mapa).find(node);
if (value == (*mapa).end()) {
return NULL;
}
return value->second;
}
void
attr_erase_from_map(void *m, void *node)
{
std::map<void *, void *> *mapa = static_cast<std::map<void *, void *> *>(m);
mapa->erase(node);
}
void
attr_clear_map_str(void *m)
{
std::map<std::string, std::string> *mapa = static_cast<std::map<std::string, std::string> *>(m);
mapa->clear();
}
static const std::vector<std::string>
explode(const std::string& s, const char& c)
{
std::string buff("");
std::vector<std::string> v;
bool found = false;
for (auto n:s) {
if (found) {
buff += n;
continue;
}
if (n != c) {
buff += n;
}
else if (n == c && buff != "") {
v.push_back(buff);
buff = "";
found = true;
}
}
if (buff != "") {
v.push_back(buff);
}
return v;
}
static std::map<std::string, std::string> *
get_requestHeaders(void *h)
{
return static_cast<std::map<std::string, std::string> *>(h);
}
static std::map<std::string, std::string, classcomp> *
get_responseHeaders(void *h)
{
return static_cast<std::map<std::string, std::string, classcomp> *>(h);
}
void
process_xhr_headers(char *head, struct mjs_xhr *x)
{
std::istringstream headers(head);
std::string http;
int status;
std::string statusText;
std::string line;
std::getline(headers, line);
std::istringstream linestream(line);
linestream >> http >> status >> statusText;
auto responseHeaders = get_responseHeaders(x->responseHeaders);
while (1) {
std::getline(headers, line);
if (line.empty()) {
break;
}
std::vector<std::string> v = explode(line, ':');
if (v.size() == 2) {
char *value = stracpy(v[1].c_str());
if (!value) {
continue;
}
char *header = stracpy(v[0].c_str());
if (!header) {
mem_free(value);
continue;
}
char *normalized_value = normalize(value);
bool found = false;
for (auto h: *responseHeaders) {
const std::string hh = h.first;
if (!strcasecmp(hh.c_str(), header)) {
(*responseHeaders)[hh] = (*responseHeaders)[hh] + ", " + normalized_value;
found = true;
break;
}
}
if (!found) {
(*responseHeaders)[header] = normalized_value;
}
mem_free(header);
mem_free(value);
}
}
x->status = status;
mem_free_set(&x->statusText, stracpy(statusText.c_str()));
}
void
set_xhr_header(char *normalized_value, const char *h_name, struct mjs_xhr *x)
{
bool found = false;
auto requestHeaders = get_requestHeaders(x->requestHeaders);
for (auto h: *requestHeaders) {
const std::string hh = h.first;
if (!strcasecmp(hh.c_str(), h_name)) {
(*requestHeaders)[hh] = (*requestHeaders)[hh] + ", " + normalized_value;
found = true;
break;
}
}
if (!found) {
(*requestHeaders)[h_name] = normalized_value;
}
}
char *
get_output_headers(struct mjs_xhr *x)
{
std::string output = "";
auto responseHeaders = get_responseHeaders(x->responseHeaders);
for (auto h: *responseHeaders) {
output += h.first + ": " + h.second + "\r\n";
}
return memacpy(output.c_str(), output.length());
}
char *
get_output_header(const char *header_name, struct mjs_xhr *x)
{
std::string output = "";
auto responseHeaders = get_responseHeaders(x->responseHeaders);
for (auto h: *responseHeaders) {
if (!strcasecmp(header_name, h.first.c_str())) {
output = h.second;
break;
}
}
if (!output.empty()) {
return memacpy(output.c_str(), output.length());
}
return NULL;
}
const std::map<std::string, bool> good = {
{ "background", true },
{ "background-color", true },
{ "color", true },
{ "display", true },
{ "font-style", true },
{ "font-weight", true },
{ "list-style", true },
{ "list-style-type", true },
{ "text-align", true },
{ "text-decoration", true },
{ "white-space", true }
};
static std::string
trimString(std::string str)
{
const std::string whiteSpaces = " \t\n\r\f\v";
// Remove leading whitespace
size_t first_non_space = str.find_first_not_of(whiteSpaces);
str.erase(0, first_non_space);
// Remove trailing whitespace
size_t last_non_space = str.find_last_not_of(whiteSpaces);
str.erase(last_non_space + 1);
return str;
}
void *
set_elstyle(const char *text)
{
if (!text || !*text) {
return NULL;
}
std::stringstream str(text);
std::string word;
std::string param, value;
std::map<std::string, std::string> *css = NULL;
while (!str.eof()) {
getline(str, word, ';');
std::stringstream params(word);
getline(params, param, ':');
getline(params, value, ':');
param = trimString(param);
value = trimString(value);
if (good.find(param) != good.end()) {
if (!css) {
css = new std::map<std::string, std::string>;
}
if (css) {
(*css)[param] = value;
}
}
}
return (void *)css;
}
char *
get_elstyle(void *m)
{
std::map<std::string, std::string> *css = static_cast<std::map<std::string, std::string> *>(m);
std::string delimiter("");
std::stringstream output("");
std::map<std::string, std::string>::iterator it;
char *res = NULL;
for (it = css->begin(); it != css->end(); it++) {
output << delimiter << it->first << ":" << it->second;
delimiter = ";";
}
res = stracpy(output.str().c_str());
css->clear();
delete css;
return res;
}
char *
get_css_value(const char *text, const char *param)
{
void *m = set_elstyle(text);
char *res = NULL;
if (!m) {
return stracpy("");
}
std::map<std::string, std::string> *css = static_cast<std::map<std::string, std::string> *>(m);
if (css->find(param) != css->end()) {
res = stracpy((*css)[param].c_str());
} else {
res = stracpy("");
}
css->clear();
delete css;
return res;
}
char *
set_css_value(const char *text, const char *param, const char *value)
{
void *m = set_elstyle(text);
std::map<std::string, std::string> *css = NULL;
if (m) {
css = static_cast<std::map<std::string, std::string> *>(m);
if (good.find(param) != good.end()) {
(*css)[param] = value;
}
return get_elstyle(m);
}
if (good.find(param) != good.end()) {
css = new std::map<std::string, std::string>;
if (!css) {
return stracpy("");
}
(*css)[param] = value;
return get_elstyle((void *)css);
}
return stracpy("");
}

View File

@ -34,8 +34,6 @@ void *attr_find_in_map(void *m, void *node);
void attr_erase_from_map(void *m, void *node);
void attr_clear_map(void *m);
void attr_clear_map_str(void *m);
void delete_map_str(void *m);
void attr_delete_map(void *m);

View File

@ -1,2 +1,2 @@
srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'document.c', 'element.c', 'form.c', 'forms.c', 'history.c', 'implementation.c', 'input.c', 'keyboard.c',
'localstorage.c', 'location.c', 'mapa.cpp', 'message.c', 'navigator.c', 'nodelist.c', 'screen.c', 'style.c', 'unibar.c', 'window.c', 'xhr.c')
'localstorage.c', 'location.c', 'mapa.c', 'message.c', 'navigator.c', 'nodelist.c', 'screen.c', 'style.c', 'unibar.c', 'window.c', 'xhr.c')

View File

@ -134,9 +134,6 @@ mjs_xhr_finalizer(js_State *J, void *data)
mem_free_if(xhr->statusText);
mem_free_if(xhr->upload);
attr_clear_map_str(xhr->responseHeaders);
attr_clear_map_str(xhr->requestHeaders);
if (xhr->onabort) js_unref(J, xhr->onabort);
if (xhr->onerror) js_unref(J, xhr->onerror);
if (xhr->onload) js_unref(J, xhr->onload);
@ -477,8 +474,12 @@ mjs_xhr_open(js_State *J)
// TODO terminate fetch
xhr->isSend = false;
xhr->isUpload = false;
attr_clear_map(xhr->requestHeaders);
attr_clear_map(xhr->responseHeaders);
delete_map_str(xhr->requestHeaders);
delete_map_str(xhr->responseHeaders);
xhr->requestHeaders = attr_create_new_requestHeaders_map();
xhr->responseHeaders = attr_create_new_responseHeaders_map();
mem_free_set(&xhr->response, NULL);
mem_free_set(&xhr->responseText, NULL);
xhr->responseLength = 0;