diff options
Diffstat (limited to 'src/libstddjb/ip6_fmt.c')
-rw-r--r-- | src/libstddjb/ip6_fmt.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/libstddjb/ip6_fmt.c b/src/libstddjb/ip6_fmt.c new file mode 100644 index 0000000..afd8a21 --- /dev/null +++ b/src/libstddjb/ip6_fmt.c @@ -0,0 +1,79 @@ +/* ISC license. */ + +#include <skalibs/diuint.h> +#include <skalibs/fmtscan.h> + +#define px(c) ((j || (c)) ? (*s++ = fmtscan_asc(c), 1) : 0) + +static inline unsigned int xfmt16 (char *s, char const *key) +{ + register unsigned int j = 0 ; + j += px((unsigned char)key[0] >> 4) ; + j += px((unsigned char)key[0] & 15) ; + j += px((unsigned char)key[1] >> 4) ; + j += px((unsigned char)key[1] & 15) ; + return j ? j : (*s = '0', 1) ; +} + +static inline unsigned int find_colcol (char const *key, unsigned int *pos) +{ + diuint z[4] = { DIUINT_ZERO, DIUINT_ZERO, DIUINT_ZERO, DIUINT_ZERO } ; + unsigned int j = 0 ; + unsigned int max = 0 ; + register int iszero = 0 ; + register unsigned int i = 0 ; + for ( ; i < 8 ; i++) + { + if (key[i<<1] || key[(i<<1)+1]) + { + if (iszero) + { + iszero = 0 ; + z[j].right = i - z[j].left ; + if (z[j].right > max) max = z[j].right ; + j++ ; + } + } + else + { + if (!iszero) + { + iszero = 1 ; + z[j].left = i ; + } + } + } + if (iszero) + { + z[j].right = 8 - z[j].left ; + if (z[j].right > max) max = z[j].right ; + j++ ; + } + + if (max >= 2) + for (i = 0 ; i < j ; i++) if (z[i].right == max) return (*pos = z[i].left, max) ; + return 0 ; +} + +unsigned int ip6_fmt (char *s, char const *ip6) +{ + unsigned int w = 0 ; + register unsigned int i = 0 ; + unsigned int pos = 8 ; + unsigned int len = find_colcol(ip6, &pos) ; + for (; i < 8 ; i++) + { + if (i == pos) + { + if (!i) s[w++] = ':' ; + s[w++] = ':' ; + i += len-1 ; + } + else + { + w += xfmt16(s + w, ip6 + (i<<1)) ; + if (i < 7) s[w++] = ':' ; + } + } + return w ; +} |