summaryrefslogtreecommitdiff
path: root/src/libstddjb/ip6_fmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstddjb/ip6_fmt.c')
-rw-r--r--src/libstddjb/ip6_fmt.c79
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 ;
+}