Changeset: 61a4b1554f8a for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/61a4b1554f8a
Added Files:
clients/mapilib/writeurl.c
Modified Files:
clients/examples/C/testsfile.c
clients/mapilib/CMakeLists.txt
clients/mapilib/msettings.h
Branch: odbc_loader
Log Message:
Add msettings_write_url
diffs (truncated from 365 to 300 lines):
diff --git a/clients/examples/C/testsfile.c b/clients/examples/C/testsfile.c
--- a/clients/examples/C/testsfile.c
+++ b/clients/examples/C/testsfile.c
@@ -28,15 +28,116 @@ static int start_line = -1;
static int nstarted = 0;
static msettings *mp = NULL;
+static
+bool verify_roundtrip(const char *location)
+{
+ const char ch = '*';
+ char buffer[1000 + 1]; // + 1 canary byte
+ memset(buffer, ch, sizeof(buffer));
+ const size_t buffer_size = sizeof(buffer) - 1;
+
+ size_t length = msettings_write_url(mp, buffer, buffer_size);
+ if (length == 0) {
+ fprintf(stderr, "%s: msettings_write_url returned 0\n",
location);
+ return false;
+ }
+ if (length > buffer_size - 1) {
+ fprintf(stderr, "%s: Reconstructed the URL unexpectedly large:
%zu\n", location, length);
+ return false;
+ }
+ if (memchr(buffer, '\0', buffer_size) == NULL) {
+ fprintf(stderr, "%s: msettings_write_url didn't NUL terminate
the result\n", location);
+ return false;
+ }
+ if (buffer[buffer_size] != ch) {
+ fprintf(stderr, "%s: msettting_write_url wrote beyond the end
of the buffer\n", location);
+ return false;
+ }
+
+ msettings *tmp = msettings_create();
+ if (tmp == NULL) {
+ fprintf(stderr, "malloc failed\n");
+ return false;
+ }
+ msettings_error err = msettings_parse_url(tmp, buffer);
+ if (err) {
+ fprintf(stderr, "%s: Reconstructed URL <%s> couldn't be parsed:
%s", location, buffer, err);
+ msettings_destroy(tmp);
+ return false;
+ }
+
+ mparm parm;
+ bool ok = true;
+ for (int i = 0; (parm = mparm_enumerate(i)) != MP_UNKNOWN; i++) {
+ if (parm == MP_IGNORE)
+ continue;
+ char scratch1[100], scratch2[100];
+ const char *mp_val = msetting_as_string(mp, parm, scratch1,
sizeof(scratch1));
+ const char *tmp_val = msetting_as_string(tmp, parm, scratch2,
sizeof(scratch2));
+ if (strcmp(mp_val, tmp_val) != 0) {
+ fprintf(
+ stderr,
+ "%s: setting %s: reconstructed value <%s> !=
<%s>\n",
+ location, mparm_name(parm), tmp_val, mp_val);
+ ok = false;
+ }
+ }
+ msettings_destroy(tmp);
+ if (!ok)
+ return false;
+
+ // check if rendering to a smaller buffer returns the same length
+ // and writes a prefix of the original.
+
+ assert(length > 0); // we checked this above
+
+ char buffer2[sizeof(buffer)];
+ for (size_t shorter = length; shorter > 0; shorter--) {
+ memset(buffer2, ch, sizeof(buffer));
+ size_t n = msettings_write_url(mp, buffer2, shorter);
+ if (n != length) {
+ fprintf(
+ stderr,\
+ "%s: writing to buffer of size %zu returns %zu,
expected %zu\n",
+ location, shorter, n, length);
+ return false;
+ }
+ char *first_nul = memchr(buffer2, '\0', shorter);
+ if (first_nul == NULL) {
+ fprintf(stderr, "%s: truncated <%zu>
msettings_write_url didn't NUL terminate\n", location, shorter);
+ return false;
+ } else if (strncmp(buffer2, buffer, shorter - 1) != 0) {
+ fprintf(stderr,
+ "%s: truncated <%zu> msettings_write_url wrote <%s>
which isn't a prefix of <%s>",
+ location, shorter,
+ buffer2, buffer
+ );
+ return false;
+ }
+ for (size_t i = shorter + 1; i < sizeof(buffer); i++) {
+ if (buffer2[i] != ch) {
+ fprintf(
+ stderr,
+ "%s: truncated <%zu>
wsettings_write_url wrote beyond end of buffer (pos %zu)\n",
+ location, shorter, i);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
static bool
handle_parse_command(const char *location, char *url)
{
const char *errmsg = msettings_parse_url(mp, url);
- if (!errmsg)
- return true;
+ if (errmsg) {
+ fprintf(stderr, "%s: %s\n", location, errmsg);
+ return false;
+ }
- fprintf(stderr, "%s: %s\n", location, errmsg);
- return false;
+ return verify_roundtrip(location);
}
static bool
@@ -53,7 +154,7 @@ handle_accept_command(const char *locati
fprintf(stderr, "%s: URL invalid: %s\n", location, msg);
return false;
}
- return true;
+ return verify_roundtrip(location);
}
static bool
@@ -79,7 +180,10 @@ handle_set_command(const char *location,
fprintf(stderr, "%s: %s\n", location, msg);
return false;
}
- return true;
+ if (msettings_validate(mp) == NULL)
+ return verify_roundtrip(location);
+ else
+ return true;
}
static bool
diff --git a/clients/mapilib/CMakeLists.txt b/clients/mapilib/CMakeLists.txt
--- a/clients/mapilib/CMakeLists.txt
+++ b/clients/mapilib/CMakeLists.txt
@@ -28,6 +28,7 @@ target_sources(mapi
msettings.c
msettings_internal.h
parseurl.c
+ writeurl.c
$<$<BOOL:${HAVE_SYS_UN_H}>:connect_unix.c>
$<$<BOOL:${OPENSSL_FOUND}>:connect_openssl.c>
$<$<BOOL:${OPENSSL_FOUND}>:$<$<BOOL:${WIN32}>:openssl_windows.c>>
diff --git a/clients/mapilib/msettings.h b/clients/mapilib/msettings.h
--- a/clients/mapilib/msettings.h
+++ b/clients/mapilib/msettings.h
@@ -167,6 +167,13 @@ mapi_export msettings_error msetting_set
/* update the msettings from the URL. */
mapi_export msettings_error msettings_parse_url(msettings *mp, const char
*url);
+/* render the msettings as an URL. The result is always NUL terminated
+ * even if it's truncated. Returns the number of characters that have been
+ * written or would have been written if the buffer were large enough,
+ * excluding the trailing NUL.
+*/
+mapi_export size_t msettings_write_url(const msettings *mp, char *buffer,
size_t);
+
/* 1 = true, 0 = false, -1 = could not parse */
mapi_export int msetting_parse_bool(const char *text);
diff --git a/clients/mapilib/writeurl.c b/clients/mapilib/writeurl.c
new file mode 100644
--- /dev/null
+++ b/clients/mapilib/writeurl.c
@@ -0,0 +1,187 @@
+/*
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright 2024, 2025 MonetDB Foundation;
+ * Copyright August 2008 - 2023 MonetDB B.V.;
+ * Copyright 1997 - July 2008 CWI.
+ */
+
+#include "monetdb_config.h"
+
+#include "msettings.h"
+#include "msettings_internal.h"
+
+struct outbuf {
+ char *buffer;
+ char *end;
+ char *pos;
+ size_t logical_size;
+};
+
+static void
+ob_append1(struct outbuf *ob, char c)
+{
+ ob->logical_size += 1;
+ if (ob->pos < ob->end)
+ *ob->pos++ = c;
+}
+
+static void
+ob_append(struct outbuf *ob, const char *s)
+{
+ size_t len = strlen(s);
+ ob->logical_size += len;
+ size_t avail = ob->end - ob->pos;
+ if (avail < len)
+ len = avail;
+ memcpy(ob->pos, s, len);
+ ob->pos += len;
+}
+
+static void
+ob_append_escaped(struct outbuf *ob, const char *text, bool escape_colon)
+{
+ const char *hex = "0123456789abcdef";
+ for (const char *s = text; *s; s++) {
+ int c = *s;
+ bool must_escape = false;
+ switch (c) {
+ case '#':
+ case '&':
+ case '=':
+ case '/':
+ case '?':
+ case '[':
+ case ']':
+ case '@':
+ case '%':
+ must_escape = true;
+ break;
+ case ':':
+ must_escape = escape_colon;
+ break;
+ default:
+ break;
+ }
+ if (must_escape) {
+ int lo = (c & 0x0F);
+ int hi = (c & 0xF0) >> 4;
+ ob_append1(ob, '%');
+ ob_append1(ob, hex[hi]);
+ ob_append1(ob, hex[lo]);
+ } else {
+ ob_append1(ob, c);
+ }
+ }
+}
+
+static void ob_printf(struct outbuf *ob, const char *fmt, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+
+static void
+ob_printf(struct outbuf *ob, const char *fmt, ...)
+{
+ va_list ap;
+ size_t avail = ob->end - ob->pos;
+
+ // vsnprintf wants to write the NUL so we use avail+1.
+ // (we left room for that)
+ va_start(ap, fmt);
+ int n = vsnprintf(ob->pos, avail + 1, fmt, ap);
+ va_end(ap);
+ assert(n >= 0);
+ size_t delta = (size_t)n;
+ ob->logical_size += delta;
+ ob->pos += (delta <= avail ? delta : avail);
+}
+
+static void
+format_url(struct outbuf *ob, const msettings *mp)
+{
+ ob_append(ob, msetting_bool(mp, MP_TLS) ? "monetdbs": "monetdb");
+ ob_append(ob, "://");
+
+ const char *host = msetting_string(mp, MP_HOST);
+ if (*host == '\0') {
+ ob_append(ob, "localhost");
+ } else if (strcmp(host, "localhost") == 0) {
+ ob_append(ob, "localhost.");
+ } else if (strchr(host, ':')) {
+ ob_append1(ob, '[');
+ ob_append_escaped(ob, host, false);
+ ob_append1(ob, ']');
+ } else {
+ ob_append_escaped(ob, host, true);
+ }
+
+ long port = msetting_long(mp, MP_PORT);
+ if (port > 0 && port < 65536 && port != 50000) {
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]