C version with single pass
C version with single pass

#include <sys/types.h>
#include <limits.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>

static int helper(const char* s, uint16_t* res, int start, int i)
{
  char* t;
  unsigned long x;
  int off, size;

  if (*s == '\0' || i >= 8) {
    if (start >= 0) {
      int next;
      size = i - start;
      next = 8 - i + start;
      if (size > 0) {
	memmove(&res[next], &res[start], size*2);
	memset(&res[start], 0, (8 - i) * 2);
      }
    }
    return 0;
  } else if (*s == ':') {
    return helper(1 + s, res, i, i);
  } else {
    x = strtoul(s, &t, 16);
    if (x == ULONG_MAX && errno == ERANGE) {
      return -1;
    } else {
      res[i] = x;
    }
    if (*t) {
      s = 1 + t;
      ++i;
    } else {
      s = t;
      ++i;
    }
    return helper(s, res, start, i);
  }

  return -1;
}

int parseipv6(const char* s, uint16_t* res)
{
  const char* t;
  
  if (*s) {
    if (*s == ':') {
      t = 1 + s;
      if (*t) {
	if (*t == ':') {
	  s = 1 + t;
	  if (*s) {
	    return helper(s, res, 0, 0);
	  } else {
	    memset(res, 0, 16);
	    return 0; /* all zeros */
	  }
	} else {
	  return -1;
	}
      } else {
	return -1;
      }
    } else {
      return helper(s, res, -1, 0);
    }
  }
  return -1;
}

void dump(uint16_t* s, int n)
{
  int i;

  for (i = 0; i < n; i++) {
    if (i < n - 1) {
      printf("%x:", s[i]);
    } else {
      printf("%x\n", s[i]);
    }
  }
}

int main(int argc, char* argv[])
{
  char* line = NULL;
  uint16_t in6[16] = {0,};
  size_t size;
  ssize_t n;

  n = getline(&line, &size, stdin);
  line[n-1] = '\0';
  if (parseipv6(line, in6) < 0) {
    printf("parse error: %s\n", argv[1]);
    exit(1);
  } else {
    dump(in6, 8);
  }

  return 0;
}
wangbj/excises,wangbj/excises,wangbj/excises