LCOV - code coverage report
Current view: top level - clients/mapilib - writeurl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 92 94 97.9 %
Date: 2025-03-24 23:16:36 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024, 2025 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : 
      15             : #include "msettings.h"
      16             : #include "msettings_internal.h"
      17             : 
      18             : struct outbuf {
      19             :         char *buffer;
      20             :         char *end;
      21             :         char *pos;
      22             :         size_t logical_size;
      23             : };
      24             : 
      25             : static void
      26      309668 : ob_append1(struct outbuf *ob, char c)
      27             : {
      28      309668 :         ob->logical_size += 1;
      29      309668 :         if (ob->pos < ob->end)
      30      104810 :                 *ob->pos++ = c;
      31             : }
      32             : 
      33             : static void
      34       61691 : ob_append(struct outbuf *ob, const char *s)
      35             : {
      36       61691 :         size_t len = strlen(s);
      37       61691 :         ob->logical_size += len;
      38       61691 :         size_t avail = ob->end - ob->pos;
      39       61691 :         if (avail < len)
      40             :                 len = avail;
      41       61691 :         memcpy(ob->pos, s, len);
      42       61691 :         ob->pos += len;
      43       61691 : }
      44             : 
      45             : static void
      46       24648 : ob_append_escaped(struct outbuf *ob, const char *text, bool escape_colon)
      47             : {
      48       24648 :         const char *hex = "0123456789abcdef";
      49      269971 :         for (const char *s = text; *s; s++) {
      50      245323 :                 int c = *s;
      51      245323 :                 bool must_escape = false;
      52      245323 :                 switch (c) {
      53             :                         case '#':
      54             :                         case '&':
      55             :                         case '=':
      56             :                         case '/':
      57             :                         case '?':
      58             :                         case '[':
      59             :                         case ']':
      60             :                         case '@':
      61             :                         case '%':
      62             :                                 must_escape = true;
      63             :                                 break;
      64             :                         case ':':
      65        6946 :                                 must_escape = escape_colon;
      66        6946 :                                 break;
      67             :                         default:
      68             :                                 break;
      69             :                 }
      70        6946 :                 if (must_escape) {
      71       14064 :                         int lo = (c & 0x0F);
      72       14064 :                         int hi = (c & 0xF0) >> 4;
      73       14064 :                         ob_append1(ob, '%');
      74       14064 :                         ob_append1(ob, hex[hi]);
      75       14064 :                         ob_append1(ob, hex[lo]);
      76             :                 } else {
      77      322624 :                         ob_append1(ob, c);
      78             :                 }
      79             :         }
      80       24648 : }
      81             : 
      82             : static void ob_printf(struct outbuf *ob, const char *fmt, ...)
      83             :         __attribute__((__format__(__printf__, 2, 3)));
      84             : 
      85             : static void
      86        3536 : ob_printf(struct outbuf *ob, const char *fmt, ...)
      87             : {
      88        3536 :         va_list ap;
      89        3536 :         size_t avail = ob->end - ob->pos;
      90             : 
      91             :         // vsnprintf wants to write the NUL so we use avail+1.
      92             :         // (we left room for that)
      93        3536 :         va_start(ap, fmt);
      94        3536 :         int n = vsnprintf(ob->pos, avail + 1, fmt, ap);
      95        3536 :         va_end(ap);
      96        3536 :         assert(n >= 0);
      97        3536 :         size_t delta = (size_t)n;
      98        3536 :         ob->logical_size += delta;
      99        3536 :         ob->pos += (delta <= avail ? delta : avail);
     100        3536 : }
     101             : 
     102             : static void
     103       16826 : format_url(struct outbuf *ob, const msettings *mp)
     104             : {
     105       28114 :         ob_append(ob, msetting_bool(mp, MP_TLS) ? "monetdbs": "monetdb");
     106       16826 :         ob_append(ob, "://");
     107             : 
     108       16826 :         const char *host = msetting_string(mp, MP_HOST);
     109       16826 :         if (*host == '\0') {
     110       12553 :                 ob_append(ob, "localhost");
     111        4273 :         } else if (strcmp(host, "localhost") == 0) {
     112        1784 :                 ob_append(ob, "localhost.");
     113        2489 :         } else if (strchr(host, ':')) {
     114         178 :                 ob_append1(ob, '[');
     115         178 :                 ob_append_escaped(ob, host, false);
     116         178 :                 ob_append1(ob, ']');
     117             :         } else {
     118        2311 :                 ob_append_escaped(ob, host, true);
     119             :         }
     120             : 
     121       16826 :         long port = msetting_long(mp, MP_PORT);
     122       16826 :         if (port > 0 && port < 65536 && port != 50000) {
     123        3536 :                 ob_printf(ob, ":%ld", port);
     124             :         }
     125             : 
     126       16826 :         const char *database = msetting_string(mp, MP_DATABASE);
     127       16826 :         const char *table_schema = msetting_string(mp, MP_TABLESCHEMA);
     128       16826 :         const char *table_name = msetting_string(mp, MP_TABLE);
     129       16826 :         bool include_table_name = (table_name[0] != '\0');
     130       16826 :         bool include_table_schema = (table_schema[0] != '\0') || include_table_name;
     131       16826 :         bool include_database = (database[0] != '\0') || include_table_schema;
     132             :         if (include_database) {
     133        6194 :                 ob_append1(ob, '/');
     134        6194 :                 ob_append_escaped(ob, database, true);
     135             :         }
     136       16826 :         if (include_table_schema) {
     137        1438 :                 ob_append1(ob, '/');
     138        1438 :                 ob_append_escaped(ob, table_schema, true);
     139             :         }
     140       16826 :         if (include_table_name) {
     141         825 :                 ob_append1(ob, '/');
     142         825 :                 ob_append_escaped(ob, table_name, true);
     143             :         }
     144             : 
     145             :         char sep = '?';
     146             :         char scratch1[40], scratch2[40];
     147             :         mparm parm;
     148      521606 :         for (int i = 0; (parm = mparm_enumerate(i)) != MP_UNKNOWN; i++) {
     149      504780 :                 if (parm == MP_IGNORE || mparm_is_core(parm))
     150      134608 :                         continue;
     151      370172 :                 const char *value = msetting_as_string(mp, parm, scratch1, sizeof(scratch1));
     152      370172 :                 const char *default_value = msetting_as_string(msettings_default, parm, scratch2, sizeof(scratch2));
     153      370172 :                 if (strcmp(value, default_value) == 0)
     154      356470 :                         continue;
     155             :                 // render it
     156       13702 :                 ob_append1(ob, sep);
     157       13702 :                 sep = '&';
     158       13702 :                 ob_append(ob, mparm_name(parm));
     159       13702 :                 ob_append1(ob, '=');
     160       13702 :                 ob_append_escaped(ob, value, true);
     161             :         }
     162       16826 : }
     163             : 
     164             : size_t
     165       16826 : msettings_write_url(const msettings *mp, char *buffer, size_t buffer_size)
     166             : {
     167       16826 :         char scratch[10];
     168       16826 :         if (buffer_size == 0) {
     169           0 :                 buffer = scratch;
     170           0 :                 buffer_size = sizeof(scratch);
     171             :         }
     172             : 
     173       16826 :         struct outbuf ob = {
     174             :                 .buffer = buffer,
     175       16826 :                 .end = buffer + buffer_size - 1,
     176             :                 .pos = buffer,
     177             :                 .logical_size = 0,
     178             :         };
     179             :         // to ease debugging
     180       16826 :         *ob.end = '\0';
     181             : 
     182       16826 :         format_url(&ob, mp);
     183             : 
     184       16826 :         assert(ob.pos <= ob.end);
     185       16826 :         *ob.pos = '\0';
     186       16826 :         return ob.logical_size;
     187             : }

Generated by: LCOV version 1.14