+#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "utils.h"
+
+static __inline__ u_int16_t dn_ntohs(u_int16_t addr)
+{
+ union {
+ u_int8_t byte[2];
+ u_int16_t word;
+ } u;
+
+ u.word = addr;
+ return ((u_int16_t)u.byte[0]) | (((u_int16_t)u.byte[1]) << 8);
+}
+
+static __inline__ int do_digit(char *str, u_int16_t *addr, u_int16_t scale, size_t *pos, size_t len, int *started)
+{
+ u_int16_t tmp = *addr / scale;
+
+ if (*pos == len)
+ return 1;
+
+ if (((tmp) > 0) || *started || (scale == 1)) {
+ *str = tmp + '0';
+ *started = 1;
+ (*pos)++;
+ *addr -= (tmp * scale);
+ }
+
+ return 0;
+}
+
+
+static const char *dnet_ntop1(const struct dn_naddr *dna, char *str, size_t len)
+{
+ u_int16_t addr = dn_ntohs(*(u_int16_t *)dna->a_addr);
+ u_int16_t area = addr >> 10;
+ size_t pos = 0;
+ int started = 0;
+
+ if (dna->a_len != 2)
+ return NULL;
+
+ addr &= 0x03ff;
+
+ if (len == 0)
+ return str;
+
+ if (do_digit(str + pos, &area, 10, &pos, len, &started))
+ return str;
+
+ if (do_digit(str + pos, &area, 1, &pos, len, &started))
+ return str;
+
+ if (pos == len)
+ return str;
+
+ *(str + pos) = '.';
+ pos++;
+ started = 0;
+
+ if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
+ return str;
+
+ if (do_digit(str + pos, &addr, 100, &pos, len, &started))
+ return str;
+
+ if (do_digit(str + pos, &addr, 10, &pos, len, &started))
+ return str;
+
+ if (do_digit(str + pos, &addr, 1, &pos, len, &started))
+ return str;
+
+ if (pos == len)
+ return str;
+
+ *(str + pos) = 0;
+
+ return str;
+}
+
+
+const char *dnet_ntop(int af, const void *addr, char *str, size_t len)
+{
+ switch(af) {
+ case AF_DECnet:
+ errno = 0;
+ return dnet_ntop1((struct dn_naddr *)addr, str, len);
+ default:
+ errno = EAFNOSUPPORT;
+ }
+
+ return NULL;
+}
+
+