feat: ports - netsurf with the monkey frontend
Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_018Ae69wJS7sueQMUwNxV3nX
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
# NetSurf for MontaukOS -- monkey frontend
|
||||
#
|
||||
# Upstream: https://github.com/netsurf-browser/netsurf (official mirror of
|
||||
# git.netsurf-browser.org; submodule at upstream/, pinned).
|
||||
#
|
||||
# monkey is NetSurf's headless, script-driven frontend: it drives the full
|
||||
# browser core (HTML parse -> CSS cascade -> layout) and reports through a
|
||||
# line protocol on stdout instead of drawing. That makes it the right first
|
||||
# target -- no graphics, no fonts, and no fetcher required.
|
||||
#
|
||||
# CONFIGURATION
|
||||
# NETSURF_USE_CURL=NO no libcurl port; the built-in file/about/data
|
||||
# fetchers remain, which is enough for file:// URLs.
|
||||
# fetch_montauk will register alongside them later.
|
||||
# NETSURF_USE_OPENSSL=NO reached only through curl. BearSSL is the eventual
|
||||
# answer, via the fetcher rather than through here.
|
||||
# NETSURF_USE_DUKTAPE=NO no JavaScript; also avoids the nsgenbind host tool.
|
||||
# NETSURF_USE_PNG/JPEG/ no ports for these codecs yet. GIF and BMP are on,
|
||||
# JPEGXL/WEBP=NO since libnsgif and libnsbmp are in the sysroot.
|
||||
# NETSURF_FS_BACKING_STORE=YES NOT optional for monkey: frontends/monkey/
|
||||
# main.c references filesystem_llcache_table
|
||||
# unconditionally, and that lives in
|
||||
# content/fs_backing_store.c. The config.h patch
|
||||
# already tells NetSurf we lack dirfd/unlinkat/
|
||||
# fstatat, so it uses its portable fallbacks.
|
||||
# NETSURF_USE_LIBICONV_PLUG=YES means "iconv is already available, do not
|
||||
# link -liconv" -- true here, since compat/iconv.c
|
||||
# provides it inside libnscompat.a.
|
||||
#
|
||||
# COMPAT SHIMS (compat/) stand in for headers MontaukOS has no equivalent of:
|
||||
# sockets, select, inet, and a stub <curl/curl.h> that exists only because
|
||||
# content/fetch.c includes curl's header unguarded. See those files -- each
|
||||
# says what it does and does not do.
|
||||
#
|
||||
# HOST TOOLS: perl, python3. (gperf is needed by libhubbub, not here.)
|
||||
|
||||
UPSTREAM := upstream
|
||||
# Absolute: the sub-make runs with -C upstream, so a relative include path
|
||||
# would resolve against the checkout rather than this port.
|
||||
COMPAT := $(CURDIR)/compat
|
||||
|
||||
PORT_NAME := netsurf
|
||||
|
||||
include ../../mk/port.mk
|
||||
|
||||
# NetSurf's own Makefile derives HOST from uname and picks its own build
|
||||
# directory, so BUILDDIR/HOST from port.mk do not apply here. The binary is
|
||||
# dropped at the top of the checkout, not inside build/.
|
||||
NS_BUILD_OUT := $(UPSTREAM)/nsmonkey
|
||||
|
||||
# Where the binary and its resources land on MontaukOS. NetSurf cannot start
|
||||
# without its resources (Messages, default.css, quirks.css ...), so the
|
||||
# resource path is compiled in and the tree is installed alongside.
|
||||
NS_RESPATH := 0:/os/netsurf/
|
||||
NS_INSTALL := $(MONTAUKOS)/programs/bin/os
|
||||
|
||||
# libutf8proc installs its header to include/libutf8proc/ but its .pc
|
||||
# advertises only -I${includedir}, while utils/idna.c includes <utf8proc.h>.
|
||||
# Add the subdirectory here rather than staging a duplicate copy of the header.
|
||||
NETSURF_CFLAGS := \
|
||||
$(PORT_CFLAGS_COMMON) \
|
||||
-I $(COMPAT) \
|
||||
-I $(PORT_SYSROOT_INC)/libutf8proc
|
||||
|
||||
NETSURF_ARGS := \
|
||||
TARGET=monkey \
|
||||
NSSHARED=$(NS_BUILDSYSTEM) \
|
||||
CC=$(CC) \
|
||||
AR=$(AR) \
|
||||
NETSURF_USE_CURL=NO \
|
||||
NETSURF_USE_OPENSSL=NO \
|
||||
NETSURF_USE_DUKTAPE=NO \
|
||||
NETSURF_USE_PNG=NO \
|
||||
NETSURF_USE_JPEG=NO \
|
||||
NETSURF_USE_JPEGXL=NO \
|
||||
NETSURF_USE_WEBP=NO \
|
||||
NETSURF_USE_VIDEO=NO \
|
||||
NETSURF_USE_LIBICONV_PLUG=YES \
|
||||
NETSURF_MONKEY_RESOURCES=$(NS_RESPATH) \
|
||||
NETSURF_FS_BACKING_STORE=YES
|
||||
|
||||
# compat/iconv.c is the only shim needing a translation unit of its own (the
|
||||
# rest are header-only). It goes into a small archive placed FIRST in LDFLAGS:
|
||||
# NetSurf appends its own pkg-config libraries after the environment's value,
|
||||
# so -lparserutils lands to the right of this archive and resolves the symbols
|
||||
# it references.
|
||||
COMPAT_LIB := $(CURDIR)/compat/libnscompat.a
|
||||
|
||||
$(COMPAT_LIB): compat/iconv.c compat/iconv.h
|
||||
$(CC) $(NETSURF_CFLAGS) -std=gnu99 -c compat/iconv.c -o compat/iconv.o
|
||||
$(AR) rcs $@ compat/iconv.o
|
||||
@echo "Built: $@"
|
||||
|
||||
.PHONY: all clean netsurf-build
|
||||
all: netsurf-build
|
||||
|
||||
netsurf-build: $(COMPAT_LIB)
|
||||
@$(call ns_patch,$(UPSTREAM))
|
||||
CFLAGS="$(NETSURF_CFLAGS)" LDFLAGS="$(COMPAT_LIB)" $(NS_ENV) \
|
||||
$(NS_MAKE) -C $(UPSTREAM) $(NETSURF_ARGS)
|
||||
@test -f $(NS_BUILD_OUT) || { echo "netsurf: expected $(NS_BUILD_OUT)" >&2; exit 1; }
|
||||
@echo "Built: $(NS_BUILD_OUT) ($$(stat -c%s $(NS_BUILD_OUT)) bytes)"
|
||||
|
||||
# Install as a MontaukOS system program plus its resource tree. Not an app
|
||||
# bundle: monkey is a console REPL with no GUI, so it carries no manifest and
|
||||
# no .port marker -- remember to uninstall before cutting a release ISO.
|
||||
.PHONY: install uninstall
|
||||
install: netsurf-build
|
||||
mkdir -p $(NS_INSTALL)/netsurf
|
||||
cp $(NS_BUILD_OUT) $(NS_INSTALL)/nsmonkey.elf
|
||||
cp -r $(UPSTREAM)/frontends/monkey/res/. $(NS_INSTALL)/netsurf/
|
||||
@echo "installed: 0:/os/nsmonkey.elf + 0:/os/netsurf/ resources"
|
||||
|
||||
uninstall:
|
||||
rm -rf $(NS_INSTALL)/nsmonkey.elf $(NS_INSTALL)/netsurf
|
||||
@echo "removed nsmonkey.elf and its resources"
|
||||
|
||||
clean:
|
||||
@$(NS_ENV) $(NS_MAKE) -C $(UPSTREAM) $(NETSURF_ARGS) clean >/dev/null 2>&1 || true
|
||||
@git -C $(UPSTREAM) checkout -- . 2>/dev/null || true
|
||||
rm -rf $(UPSTREAM)/build-Linux-monkey
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Minimal <arpa/inet.h> for the MontaukOS NetSurf port.
|
||||
*
|
||||
* NetSurf uses inet_pton() only to recognise IP literals in URLs
|
||||
* (content/urldb.c, utils/utils.c) -- it never opens a socket with the result.
|
||||
* A self-contained parser is therefore enough, and keeps this out of the
|
||||
* MontaukOS libc, where a partial implementation would be misleading.
|
||||
*
|
||||
* static inline throughout: these headers are included by a handful of
|
||||
* translation units and NetSurf builds with -Werror, so a non-static
|
||||
* definition would either collide at link time or warn when unused.
|
||||
*/
|
||||
#ifndef _MONTAUK_COMPAT_ARPA_INET_H_
|
||||
#define _MONTAUK_COMPAT_ARPA_INET_H_
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Parse a dotted-quad into 4 network-order bytes. Returns 1 on success. */
|
||||
static inline int montauk_inet_pton4(const char *src, uint8_t *dst)
|
||||
{
|
||||
uint32_t octet = 0;
|
||||
int digits = 0;
|
||||
int seen = 0;
|
||||
uint8_t out[4];
|
||||
|
||||
for (;;) {
|
||||
char c = *src++;
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
if (digits == 3)
|
||||
return 0;
|
||||
/* a leading zero is not accepted (023 is ambiguous) */
|
||||
if (digits == 1 && out[seen] == 0)
|
||||
return 0;
|
||||
octet = octet * 10 + (uint32_t)(c - '0');
|
||||
if (octet > 255)
|
||||
return 0;
|
||||
out[seen] = (uint8_t)octet;
|
||||
digits++;
|
||||
} else if (c == '.' || c == '\0') {
|
||||
if (digits == 0)
|
||||
return 0;
|
||||
if (c == '\0') {
|
||||
if (seen != 3)
|
||||
return 0;
|
||||
memcpy(dst, out, 4);
|
||||
return 1;
|
||||
}
|
||||
if (seen == 3)
|
||||
return 0;
|
||||
seen++;
|
||||
octet = 0;
|
||||
digits = 0;
|
||||
out[seen] = 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an IPv6 literal, including "::" compression and a trailing
|
||||
* dotted-quad (e.g. ::ffff:192.0.2.1). Returns 1 on success.
|
||||
*/
|
||||
static inline int montauk_inet_pton6(const char *src, uint8_t *dst)
|
||||
{
|
||||
uint8_t out[16];
|
||||
int head = 0; /* bytes written before "::" */
|
||||
int tail = 0; /* bytes buffered after "::" */
|
||||
uint8_t tailbuf[16];
|
||||
int seen_compress = 0;
|
||||
uint8_t *cur = out;
|
||||
int *curlen = &head;
|
||||
|
||||
memset(out, 0, sizeof(out));
|
||||
|
||||
if (src[0] == ':') {
|
||||
if (src[1] != ':')
|
||||
return 0;
|
||||
src += 2;
|
||||
seen_compress = 1;
|
||||
cur = tailbuf;
|
||||
curlen = &tail;
|
||||
if (*src == '\0')
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
uint32_t group = 0;
|
||||
int digits = 0;
|
||||
|
||||
/* a dotted-quad may only appear as the final component */
|
||||
if (strchr(src, '.') != NULL) {
|
||||
const char *p = src;
|
||||
int dots = 0;
|
||||
while (*p != '\0' && *p != ':') {
|
||||
if (*p == '.')
|
||||
dots++;
|
||||
p++;
|
||||
}
|
||||
if (dots == 3 && *p == '\0') {
|
||||
if (*curlen + 4 > 16)
|
||||
return 0;
|
||||
if (montauk_inet_pton4(src, cur + *curlen) == 0)
|
||||
return 0;
|
||||
*curlen += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (*src != '\0' && *src != ':') {
|
||||
char c = *src;
|
||||
uint32_t v;
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
v = (uint32_t)(c - '0');
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
v = (uint32_t)(c - 'a' + 10);
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
v = (uint32_t)(c - 'A' + 10);
|
||||
else
|
||||
return 0;
|
||||
|
||||
group = group * 16 + v;
|
||||
if (++digits > 4)
|
||||
return 0;
|
||||
src++;
|
||||
}
|
||||
|
||||
if (digits == 0)
|
||||
return 0;
|
||||
if (*curlen + 2 > 16)
|
||||
return 0;
|
||||
|
||||
cur[(*curlen)++] = (uint8_t)(group >> 8);
|
||||
cur[(*curlen)++] = (uint8_t)(group & 0xff);
|
||||
|
||||
if (*src == '\0')
|
||||
break;
|
||||
|
||||
src++; /* consume ':' */
|
||||
|
||||
if (*src == ':') {
|
||||
if (seen_compress)
|
||||
return 0;
|
||||
seen_compress = 1;
|
||||
src++;
|
||||
cur = tailbuf;
|
||||
curlen = &tail;
|
||||
if (*src == '\0')
|
||||
break;
|
||||
} else if (*src == '\0') {
|
||||
/* trailing single colon */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (seen_compress) {
|
||||
if (head + tail > 15) /* "::" must stand for >= 1 zero group */
|
||||
return 0;
|
||||
memmove(out + 16 - tail, tailbuf, (size_t)tail);
|
||||
memset(out + head, 0, (size_t)(16 - tail - head));
|
||||
} else if (head != 16) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(dst, out, 16);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* inet_aton(). Returns non-zero on success, as BSD does.
|
||||
*
|
||||
* Only the full dotted-quad form is accepted. Historic inet_aton also takes
|
||||
* "a", "a.b", "a.b.c" and octal/hex octets, but content/urldb.c immediately
|
||||
* rejects anything without three dots (see the comment at its call site), so
|
||||
* the narrower behaviour matches how NetSurf actually uses it -- and refusing
|
||||
* octal-looking octets like "1.2.3.04" is the safer reading for a URL host.
|
||||
*/
|
||||
static inline int inet_aton(const char *cp, struct in_addr *addr)
|
||||
{
|
||||
uint8_t out[4];
|
||||
|
||||
if (cp == NULL || addr == NULL)
|
||||
return 0;
|
||||
if (montauk_inet_pton4(cp, out) != 1)
|
||||
return 0;
|
||||
|
||||
memcpy(&addr->s_addr, out, 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
if (src == NULL || dst == NULL)
|
||||
return -1;
|
||||
|
||||
if (af == AF_INET)
|
||||
return montauk_inet_pton4(src, (uint8_t *) dst);
|
||||
if (af == AF_INET6)
|
||||
return montauk_inet_pton6(src, (uint8_t *) dst);
|
||||
|
||||
return -1; /* EAFNOSUPPORT */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Stub <curl/curl.h> for the MontaukOS NetSurf port.
|
||||
*
|
||||
* This is NOT a curl implementation and nothing here can perform a fetch.
|
||||
*
|
||||
* NetSurf is built with NETSURF_USE_CURL=NO, but that configuration is not
|
||||
* well exercised upstream: content/fetch.c includes content/fetchers/curl.h
|
||||
* unconditionally and only guards the *use* of fetch_curl_register() behind
|
||||
* #ifdef WITH_CURL. That header in turn includes <curl/curl.h> and declares
|
||||
* `extern CURLM *fetch_curl_multi`, so the type must exist for the
|
||||
* translation unit to compile even though no curl code is built.
|
||||
*
|
||||
* Supplying this stub keeps the port free of patches against upstream. The
|
||||
* alternative -- guarding the include in content/fetch.c -- is a one-line
|
||||
* change but starts a patch series that every future NetSurf update has to
|
||||
* be rebased onto.
|
||||
*
|
||||
* When fetch_montauk lands it registers itself the same way fetch_curl would,
|
||||
* and this file stays exactly as it is.
|
||||
*/
|
||||
#ifndef _MONTAUK_COMPAT_CURL_CURL_H_
|
||||
#define _MONTAUK_COMPAT_CURL_CURL_H_
|
||||
|
||||
/* Opaque: only ever named in a declaration that is never defined or used. */
|
||||
typedef void CURLM;
|
||||
typedef void CURL;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* iconv() for the MontaukOS NetSurf port, implemented over libparserutils'
|
||||
* charset codecs. See iconv.h for why.
|
||||
*
|
||||
* Structure: one codec decodes the source charset to UCS-4, a second encodes
|
||||
* UCS-4 to the destination charset. iconv() pumps a small stack buffer of
|
||||
* UCS-4 between them so neither side needs an unbounded intermediate.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <parserutils/charset/codec.h>
|
||||
#include <parserutils/errors.h>
|
||||
|
||||
#include "iconv.h"
|
||||
|
||||
/* UCS-4 code points staged between decode and encode, per inner iteration. */
|
||||
#define STAGE_POINTS 64
|
||||
|
||||
struct montauk_iconv {
|
||||
parserutils_charset_codec *from; /* source charset -> UCS-4 */
|
||||
parserutils_charset_codec *to; /* UCS-4 -> dest charset */
|
||||
};
|
||||
|
||||
/*
|
||||
* Strip glibc's "//TRANSLIT" / "//IGNORE" suffixes, which libparserutils does
|
||||
* not understand. Returns a malloc'd bare charset name.
|
||||
*/
|
||||
static char *strip_suffix(const char *name)
|
||||
{
|
||||
const char *sep;
|
||||
size_t len;
|
||||
char *out;
|
||||
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
sep = strstr(name, "//");
|
||||
len = (sep != NULL) ? (size_t) (sep - name) : strlen(name);
|
||||
|
||||
out = malloc(len + 1);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(out, name, len);
|
||||
out[len] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
static parserutils_charset_codec *make_codec(const char *name)
|
||||
{
|
||||
parserutils_charset_codec *codec = NULL;
|
||||
parserutils_charset_codec_optparams params;
|
||||
char *bare;
|
||||
|
||||
bare = strip_suffix(name);
|
||||
if (bare == NULL)
|
||||
return NULL;
|
||||
|
||||
if (parserutils_charset_codec_create(bare, &codec) != PARSERUTILS_OK) {
|
||||
free(bare);
|
||||
return NULL;
|
||||
}
|
||||
free(bare);
|
||||
|
||||
/*
|
||||
* LOOSE: substitute unrepresentable characters instead of aborting.
|
||||
* NetSurf renders best-effort; a hard failure mid-document is worse
|
||||
* than a replacement character.
|
||||
*/
|
||||
params.error_mode.mode = PARSERUTILS_CHARSET_CODEC_ERROR_LOOSE;
|
||||
(void) parserutils_charset_codec_setopt(codec,
|
||||
PARSERUTILS_CHARSET_CODEC_ERROR_MODE, ¶ms);
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
||||
iconv_t iconv_open(const char *tocode, const char *fromcode)
|
||||
{
|
||||
struct montauk_iconv *cd;
|
||||
|
||||
cd = calloc(1, sizeof(*cd));
|
||||
if (cd == NULL) {
|
||||
errno = ENOMEM;
|
||||
return (iconv_t) -1;
|
||||
}
|
||||
|
||||
cd->from = make_codec(fromcode);
|
||||
cd->to = make_codec(tocode);
|
||||
|
||||
if (cd->from == NULL || cd->to == NULL) {
|
||||
if (cd->from != NULL)
|
||||
parserutils_charset_codec_destroy(cd->from);
|
||||
if (cd->to != NULL)
|
||||
parserutils_charset_codec_destroy(cd->to);
|
||||
free(cd);
|
||||
errno = EINVAL; /* unsupported conversion */
|
||||
return (iconv_t) -1;
|
||||
}
|
||||
|
||||
return (iconv_t) cd;
|
||||
}
|
||||
|
||||
int iconv_close(iconv_t handle)
|
||||
{
|
||||
struct montauk_iconv *cd = (struct montauk_iconv *) handle;
|
||||
|
||||
if (cd == NULL || handle == (iconv_t) -1) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
parserutils_charset_codec_destroy(cd->from);
|
||||
parserutils_charset_codec_destroy(cd->to);
|
||||
free(cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t iconv(iconv_t handle, char **inbuf, size_t *inbytesleft,
|
||||
char **outbuf, size_t *outbytesleft)
|
||||
{
|
||||
struct montauk_iconv *cd = (struct montauk_iconv *) handle;
|
||||
size_t converted = 0;
|
||||
|
||||
if (cd == NULL || handle == (iconv_t) -1) {
|
||||
errno = EBADF;
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
/* Reset request: iconv(cd, NULL, NULL, ...) returns to initial state. */
|
||||
if (inbuf == NULL || *inbuf == NULL) {
|
||||
parserutils_charset_codec_reset(cd->from);
|
||||
parserutils_charset_codec_reset(cd->to);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*inbytesleft > 0) {
|
||||
uint8_t stage[STAGE_POINTS * 4];
|
||||
const uint8_t *src = (const uint8_t *) *inbuf;
|
||||
size_t srclen = *inbytesleft;
|
||||
uint8_t *mid = stage;
|
||||
size_t midlen = sizeof(stage);
|
||||
size_t staged;
|
||||
const uint8_t *midsrc;
|
||||
size_t midsrclen;
|
||||
uint8_t *dst;
|
||||
size_t dstlen;
|
||||
parserutils_error perr;
|
||||
|
||||
/* ---- source charset -> UCS-4 ---- */
|
||||
perr = parserutils_charset_codec_decode(cd->from,
|
||||
&src, &srclen, &mid, &midlen);
|
||||
|
||||
staged = sizeof(stage) - midlen;
|
||||
|
||||
if (staged == 0) {
|
||||
/* nothing decoded: classify why and stop */
|
||||
if (perr == PARSERUTILS_NEEDDATA)
|
||||
errno = EINVAL; /* incomplete tail sequence */
|
||||
else if (perr == PARSERUTILS_INVALID)
|
||||
errno = EILSEQ; /* malformed input */
|
||||
else if (perr == PARSERUTILS_NOMEM)
|
||||
errno = E2BIG;
|
||||
else
|
||||
errno = EILSEQ;
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
/* ---- UCS-4 -> destination charset ---- */
|
||||
midsrc = stage;
|
||||
midsrclen = staged;
|
||||
dst = (uint8_t *) *outbuf;
|
||||
dstlen = *outbytesleft;
|
||||
|
||||
perr = parserutils_charset_codec_encode(cd->to,
|
||||
&midsrc, &midsrclen, &dst, &dstlen);
|
||||
|
||||
/*
|
||||
* Advance the caller's input only by what was both decoded AND
|
||||
* encoded. If the encoder ran out of output room mid-stage,
|
||||
* the undrained UCS-4 must not be counted as consumed -- the
|
||||
* caller will grow its buffer and call again.
|
||||
*/
|
||||
{
|
||||
size_t encoded_points = (staged - midsrclen) / 4;
|
||||
size_t consumed_in;
|
||||
|
||||
*outbytesleft = dstlen;
|
||||
*outbuf = (char *) dst;
|
||||
|
||||
if (midsrclen == 0) {
|
||||
/* whole stage drained: input consumed as decoded */
|
||||
consumed_in = (size_t) ((const char *) src - *inbuf);
|
||||
} else {
|
||||
/*
|
||||
* Partial drain. Re-decode from the original
|
||||
* position next time; consume nothing this
|
||||
* round beyond what actually made it out.
|
||||
*/
|
||||
if (encoded_points == 0) {
|
||||
errno = E2BIG;
|
||||
return (size_t) -1;
|
||||
}
|
||||
consumed_in = 0;
|
||||
}
|
||||
|
||||
if (consumed_in > 0) {
|
||||
*inbuf += consumed_in;
|
||||
*inbytesleft -= consumed_in;
|
||||
}
|
||||
|
||||
converted += encoded_points;
|
||||
|
||||
if (midsrclen != 0) {
|
||||
/* output was too small to take the rest */
|
||||
errno = E2BIG;
|
||||
return (size_t) -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (perr == PARSERUTILS_NOMEM) {
|
||||
errno = E2BIG;
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
if (*outbytesleft == 0 && *inbytesleft > 0) {
|
||||
errno = E2BIG;
|
||||
return (size_t) -1;
|
||||
}
|
||||
}
|
||||
|
||||
return converted;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* <iconv.h> for the MontaukOS NetSurf port.
|
||||
*
|
||||
* MontaukOS has no iconv. Rather than port GNU libiconv, this implements the
|
||||
* three-function iconv API on top of libparserutils' charset codecs, which are
|
||||
* already in the ports sysroot.
|
||||
*
|
||||
* That is a good fit rather than a bodge: libparserutils decodes a charset to
|
||||
* UCS-4 and encodes UCS-4 back out, so iconv() is decode-then-encode through a
|
||||
* UCS-4 staging buffer. The supported set is whatever libparserutils supports
|
||||
* -- UTF-8, UTF-16, ASCII, ISO-8859-x and the Windows-125x range -- which is
|
||||
* exactly the set the HTML parser can handle anyway, so nothing is lost that
|
||||
* would otherwise have worked.
|
||||
*
|
||||
* NetSurf touches iconv only from utils/utf8.c.
|
||||
*
|
||||
* NOT SUPPORTED: the "//TRANSLIT" and "//IGNORE" suffixes glibc accepts. They
|
||||
* are stripped and ignored; conversion uses libparserutils' LOOSE error mode,
|
||||
* which substitutes rather than failing.
|
||||
*/
|
||||
#ifndef _MONTAUK_COMPAT_ICONV_H_
|
||||
#define _MONTAUK_COMPAT_ICONV_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void *iconv_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
iconv_t iconv_open(const char *tocode, const char *fromcode);
|
||||
size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft,
|
||||
char **outbuf, size_t *outbytesleft);
|
||||
int iconv_close(iconv_t cd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Minimal <netinet/in.h> for the MontaukOS NetSurf port.
|
||||
* Only the address structures urldb.c and utils.c use for IP-literal parsing.
|
||||
*/
|
||||
#ifndef _MONTAUK_COMPAT_NETINET_IN_H_
|
||||
#define _MONTAUK_COMPAT_NETINET_IN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct in_addr {
|
||||
uint32_t s_addr;
|
||||
};
|
||||
|
||||
struct in6_addr {
|
||||
uint8_t s6_addr[16];
|
||||
};
|
||||
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#define INET6_ADDRSTRLEN 46
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Minimal <sys/select.h> for the MontaukOS NetSurf port.
|
||||
*
|
||||
* MontaukOS has no select(). Readiness on a socket is expressed through the
|
||||
* kernel's waitset (SYS_WAITSET_*), which is a different shape entirely, and
|
||||
* stdio descriptors are not waitable objects at all.
|
||||
*
|
||||
* NetSurf's core uses select() in exactly one place -- content/fetch.c's
|
||||
* fetch_fdset() collects descriptors from the registered fetchers, and the
|
||||
* frontend's main loop selects over them plus its own input. With
|
||||
* NETSURF_USE_CURL=NO no fetcher registers a descriptor, so the only fd that
|
||||
* ever appears is the monkey frontend's stdin (fd 0).
|
||||
*
|
||||
* That makes a useful shim possible:
|
||||
*
|
||||
* - if any read descriptor is requested, report them ready immediately and
|
||||
* let the caller block in read(). monkey is a line-driven REPL, so
|
||||
* blocking on stdin is what it wants anyway.
|
||||
* - otherwise sleep for the timeout so an idle loop does not spin.
|
||||
*
|
||||
* LIMITATION: because a requested read fd is always reported ready, scheduled
|
||||
* callbacks do not fire while the process sits idle waiting for a command.
|
||||
* That is fine for driving monkey by hand or by script, and it is wrong for
|
||||
* anything with real network activity. When fetch_montauk lands it will
|
||||
* register descriptors here and this needs replacing with a genuine
|
||||
* waitset-backed implementation.
|
||||
*/
|
||||
#ifndef _MONTAUK_COMPAT_SYS_SELECT_H_
|
||||
#define _MONTAUK_COMPAT_SYS_SELECT_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define FD_SETSIZE 64
|
||||
|
||||
typedef struct {
|
||||
unsigned long fds_bits[(FD_SETSIZE + (8 * sizeof(unsigned long)) - 1) /
|
||||
(8 * sizeof(unsigned long))];
|
||||
} fd_set;
|
||||
|
||||
#define __NFDBITS (8 * (int) sizeof(unsigned long))
|
||||
|
||||
#define FD_ZERO(s) memset((s), 0, sizeof(fd_set))
|
||||
#define FD_SET(fd, s) \
|
||||
((void) ((s)->fds_bits[(fd) / __NFDBITS] |= \
|
||||
(1UL << ((fd) % __NFDBITS))))
|
||||
#define FD_CLR(fd, s) \
|
||||
((void) ((s)->fds_bits[(fd) / __NFDBITS] &= \
|
||||
~(1UL << ((fd) % __NFDBITS))))
|
||||
#define FD_ISSET(fd, s) \
|
||||
(((s)->fds_bits[(fd) / __NFDBITS] & (1UL << ((fd) % __NFDBITS))) != 0)
|
||||
|
||||
static inline int montauk_fdset_empty(const fd_set *s)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (s == NULL)
|
||||
return 1;
|
||||
for (i = 0; i < sizeof(s->fds_bits) / sizeof(s->fds_bits[0]); i++) {
|
||||
if (s->fds_bits[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int montauk_fdset_count(const fd_set *s, int nfds)
|
||||
{
|
||||
int fd, n = 0;
|
||||
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
for (fd = 0; fd < nfds && fd < FD_SETSIZE; fd++) {
|
||||
if (FD_ISSET(fd, s))
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline int select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds, struct timeval *timeout)
|
||||
{
|
||||
int ready;
|
||||
|
||||
if (writefds != NULL)
|
||||
FD_ZERO(writefds);
|
||||
if (exceptfds != NULL)
|
||||
FD_ZERO(exceptfds);
|
||||
|
||||
if (montauk_fdset_empty(readfds) == 0) {
|
||||
/* leave readfds as-is: every requested fd is "ready" */
|
||||
return montauk_fdset_count(readfds, nfds);
|
||||
}
|
||||
|
||||
ready = 0;
|
||||
|
||||
if (timeout != NULL) {
|
||||
unsigned long usec = (unsigned long) timeout->tv_sec * 1000000UL +
|
||||
(unsigned long) timeout->tv_usec;
|
||||
if (usec != 0)
|
||||
usleep(usec);
|
||||
}
|
||||
|
||||
return ready;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Minimal <sys/socket.h> for the MontaukOS NetSurf port.
|
||||
*
|
||||
* NetSurf includes this via utils/inet.h. MontaukOS has no BSD socket layer
|
||||
* (the kernel exposes sockets as IPC handles through montauk::socket), so this
|
||||
* supplies only the few declarations NetSurf's non-curl paths actually touch:
|
||||
* the address families and socklen_t. Nothing here opens a socket.
|
||||
*/
|
||||
#ifndef _MONTAUK_COMPAT_SYS_SOCKET_H_
|
||||
#define _MONTAUK_COMPAT_SYS_SOCKET_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define AF_UNSPEC 0
|
||||
#define AF_INET 2
|
||||
#define AF_INET6 10
|
||||
|
||||
typedef uint32_t socklen_t;
|
||||
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_DGRAM 2
|
||||
|
||||
/*
|
||||
* socket() exists only so desktop/gui_factory.c compiles: it installs
|
||||
* gui_default_socket_open() into the fetch table, and that default is reached
|
||||
* only by a fetcher that opens sockets -- i.e. curl, which is not built here.
|
||||
*
|
||||
* It deliberately FAILS rather than pretending. MontaukOS sockets are IPC
|
||||
* handles obtained through montauk::socket() and are not interchangeable with
|
||||
* BSD descriptors, so any caller reaching this wants the real fetcher instead.
|
||||
* fetch_montauk will provide its own socket_open in the fetch table.
|
||||
*/
|
||||
static inline int socket(int domain, int type, int protocol)
|
||||
{
|
||||
(void) domain;
|
||||
(void) type;
|
||||
(void) protocol;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
diff --git a/utils/config.h b/utils/config.h
|
||||
index 3914771fd..09f2659d6 100644
|
||||
--- a/utils/config.h
|
||||
+++ b/utils/config.h
|
||||
@@ -119,7 +119,7 @@ char *strchrnul(const char *s, int c);
|
||||
#endif
|
||||
|
||||
#define HAVE_UTSNAME
|
||||
-#if (defined(_WIN32))
|
||||
+#if (defined(_WIN32) || defined(__montauk__))
|
||||
#undef HAVE_UTSNAME
|
||||
#endif
|
||||
|
||||
@@ -158,14 +158,14 @@ char *realpath(const char *path, char *resolved_path);
|
||||
#define HAVE_DIRFD
|
||||
#define HAVE_UNLINKAT
|
||||
#define HAVE_FSTATAT
|
||||
-#if (defined(_WIN32) || defined(__riscos__) || defined(__HAIKU__) || defined(__BEOS__) || defined(__amigaos4__) || defined(__AMIGA__) || defined(__MINT__))
|
||||
+#if (defined(_WIN32) || defined(__riscos__) || defined(__HAIKU__) || defined(__BEOS__) || defined(__amigaos4__) || defined(__AMIGA__) || defined(__MINT__) || defined(__montauk__))
|
||||
#undef HAVE_DIRFD
|
||||
#undef HAVE_UNLINKAT
|
||||
#undef HAVE_FSTATAT
|
||||
#endif
|
||||
|
||||
#define HAVE_REGEX
|
||||
-#if (defined(__serenity__))
|
||||
+#if (defined(__serenity__) || defined(__montauk__))
|
||||
#undef HAVE_REGEX
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
diff --git a/frontends/monkey/main.c b/frontends/monkey/main.c
|
||||
index 463f0bea6..578d148e4 100644
|
||||
--- a/frontends/monkey/main.c
|
||||
+++ b/frontends/monkey/main.c
|
||||
@@ -422,7 +422,12 @@ main(int argc, char **argv)
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
/* Prep the search paths */
|
||||
+#if defined(__montauk__)
|
||||
+ /* see NS_RESPATH_SEP: ':' is part of a MontaukOS drive path */
|
||||
+ respaths = nsmonkey_init_resource("${HOME}/.netsurf/;${NETSURFRES};"MONKEY_RESPATH";./frontends/monkey/res");
|
||||
+#else
|
||||
respaths = nsmonkey_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"MONKEY_RESPATH":./frontends/monkey/res");
|
||||
+#endif
|
||||
|
||||
/* initialise logging. Not fatal if it fails but not much we can do
|
||||
* about it either.
|
||||
diff --git a/utils/filepath.c b/utils/filepath.c
|
||||
index b87e2bf0d..9c4bcd34b 100644
|
||||
--- a/utils/filepath.c
|
||||
+++ b/utils/filepath.c
|
||||
@@ -325,7 +325,7 @@ filepath_path_to_strvec(const char *path)
|
||||
estart = eend = path;
|
||||
|
||||
while (strc < (MAX_RESPATH - 2)) {
|
||||
- while ( (*eend != 0) && (*eend != ':') )
|
||||
+ while ( (*eend != 0) && (*eend != NS_RESPATH_SEP) )
|
||||
eend++;
|
||||
elen = eend - estart;
|
||||
|
||||
@@ -339,7 +339,7 @@ filepath_path_to_strvec(const char *path)
|
||||
}
|
||||
|
||||
/* skip colons */
|
||||
- while (*eend == ':')
|
||||
+ while (*eend == NS_RESPATH_SEP)
|
||||
eend++;
|
||||
|
||||
/* check for termination */
|
||||
diff --git a/utils/filepath.h b/utils/filepath.h
|
||||
index 784264b33..469830a9d 100644
|
||||
--- a/utils/filepath.h
|
||||
+++ b/utils/filepath.h
|
||||
@@ -24,6 +24,22 @@
|
||||
#ifndef _NETSURF_UTILS_FILEPATH_H_
|
||||
#define _NETSURF_UTILS_FILEPATH_H_
|
||||
|
||||
+/**
|
||||
+ * Character separating elements of a resource path list.
|
||||
+ *
|
||||
+ * A colon cannot double as the list separator on platforms whose absolute
|
||||
+ * paths already contain one -- MontaukOS names drives as "N:/dir", so
|
||||
+ * "0:/os/netsurf/" would split into "0" and "/os/netsurf/", neither of which
|
||||
+ * resolves.
|
||||
+ */
|
||||
+#ifndef NS_RESPATH_SEP
|
||||
+#if defined(__montauk__)
|
||||
+#define NS_RESPATH_SEP ';'
|
||||
+#else
|
||||
+#define NS_RESPATH_SEP ':'
|
||||
+#endif
|
||||
+#endif
|
||||
+
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "utils/errors.h"
|
||||
Submodule
+1
Submodule www-client/netsurf/upstream added at 39da3c3a40
Reference in New Issue
Block a user