Changeset: ec81b283b7fc for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/ec81b283b7fc
Modified Files:
        gdk/gdk_atoms.c
Branch: default
Log Message:

Fix inet6 to string conversion

Inet6 values were rendered incorrectly, for example

    SELECT inet6 '::1'

would yield something like

    ::0:0:0:0:145


diffs (125 lines):

diff --git a/gdk/gdk_atoms.c b/gdk/gdk_atoms.c
--- a/gdk/gdk_atoms.c
+++ b/gdk/gdk_atoms.c
@@ -1776,62 +1776,81 @@ INET6toString(allocator *ma, str *retval
        (void) ma;
        const inet6 *value = VALUE;
        (void) external;
-       /* max size: strlen("1234:1234:1234:1234:1234:1234:1234:1234")+1 */
+
+       /* ensure buffer capacity. */
+       /* max size: 8 * (digit digit digit digit colon-or-nul) == 40 */
        if (*len < 40 || *retval == NULL) {
                if ((*retval = ma_alloc(ma, 40)) == NULL)
                        return -1;
                *len = 40;
        }
+
        /* find longest stretch of zeroes */
-       int rl = 0;             /* length of current stretch of zeros */
-       int rl1 = -1;           /* start of current stretch of zeros */
-       int mrl = 0;            /* length of longest stretch of zeros */
-       int mrl1 = -1;          /* start of longest stretch of zeros */
+       int run_len = 0;        /* length of current stretch of zeros */
+       int best_start = 16;    /* start of longest stretch of zeros */
+       int best_len = 0;       /* length of longest stretch of zeros */
        for (int i = 0; i < 16; i += 2) {
                if (value->hex[i] == 0 && value->hex[i + 1] == 0) {
-                       if (rl++ == 0)
-                               rl1 = i;
-               } else {
-                       if (rl > 1 && rl > mrl) {
-                               mrl = rl;
-                               mrl1 = rl1;
-                       }
-                       rl = 0;
+                       /* record it as part of a stretch of zeroes */
+                       run_len += 2;
+                       continue;
                }
+               if (run_len > best_len) {
+                       /* record new longest stretch */
+                       best_start = i - run_len;
+                       best_len = run_len;
+               }
+               /* definitely not part of a stretch of zeroes */
+               run_len = 0;
        }
-       if (rl > 1 && rl > mrl) {
-               mrl = rl;
-               mrl1 = rl1;
+       if (run_len > best_len) {
+               /* longest stretch is at the end */
+               best_start = 16 - run_len;
+               best_len = run_len;
        }
-       if (mrl1 < 0)
-               mrl1 = 16;
-       int pos = 0;
-       if (mrl1 == 0 && mrl == 10
-           && value->hex[10] == 0xFF && value->hex[11] == 0xFF) {
-               /* IPv4 address disguised as IPv6 */
-               pos += snprintf(*retval + pos, *len - pos,
+
+       /* nils should never reach us here */
+       assert(best_len < 8);
+
+       /* Special case: IPv4-mapped IPv6 address       */
+       if (best_start == 0 && best_len == 10 && value->hex[10] == 0xFF && 
value->hex[11] == 0xFF) {
+               return snprintf(*retval, *len,
                                "::ffff:%d.%d.%d.%d",
                                value->hex[12], value->hex[13],
                                value->hex[14], value->hex[15]);
-               return pos;
-       }
-       for (int i = 0; i < mrl1; i += 2) {
-               if (i > 0)
-                       (*retval)[pos++] = ':';
-               pos += snprintf(*retval + pos, *len - pos, "%x",
-                               (unsigned) ((value->hex[i] << 8) | value->hex[i 
+ 1]));
        }
-       if (mrl1 < 8) {
-               (*retval)[pos++] = ':';
-               (*retval)[pos++] = ':';
+
+       /* render it as colon-separated quads */
+       char *p = *retval;
+       for (int i = 0; i < 16; i += 2) {
+               /* In principle, each iteration prints a hex quad followed by a
+                * colon, but the stretch is treated specially. */
+               if (i != best_start) {
+                       unsigned int quad = value->hex[i] * 256 + value->hex[i 
+ 1];
+                       static const char hexdigits[17] = "0123456789abcdef";
+                       *p = hexdigits[value->hex[i] >> 4];
+                       p += quad >= 0x1000;
+                       *p = hexdigits[value->hex[i] & 0xF];
+                       p += quad >= 0x0100;
+                       *p = hexdigits[value->hex[i + 1] >> 4];
+                       p += quad >= 0x0010;
+                       *p++ = hexdigits[value->hex[i + 1] & 0xF];
+                       if (i < 14)
+                               *p++ = ':';
+               } else {
+                       /* the stretch */
+                       if (i == 0)
+                               *p++ = ':';
+                       *p++ = ':';
+                       i += best_len - 2;
+               }
        }
-       for (int i = mrl1 + mrl; i < 16; i += 2) {
-               pos += snprintf(*retval + pos, *len - pos, "%x",
-                               (unsigned) ((value->hex[i] << 8) | value->hex[i 
+ 1]));
-               if (i < 15)
-                       (*retval)[pos++] = ':';
-       }
-       return pos;
+       *p = '\0';
+
+       /* we must have written at least 3 characters followed by a NUL */
+       assert(p - *retval >= 3);
+
+       return p - *retval;
 }
 
 static const blob blob_nil = {
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to