ref: e5e6a729ddb6956d520c87cb5905b3515323dccc
parent: d2b3e2f55a52df45c8e9c0b043763809f0001e69
parent: 33682a58857cc79b967ed37b39845f80a03f6958
author: cinap_lenrek <[email protected]>
date: Tue Sep 25 16:45:11 EDT 2018
merge
--- a/sys/include/libc.h
+++ b/sys/include/libc.h
@@ -527,6 +527,9 @@
extern NetConnInfo* getnetconninfo(char*, int);
extern void freenetconninfo(NetConnInfo*);
+extern char* idn2utf(char*, char*, int);
+extern char* utf2idn(char*, char*, int);
+
/*
* system calls
*
--- a/sys/src/cmd/ip/dhcp6d.c
+++ b/sys/src/cmd/ip/dhcp6d.c
@@ -562,6 +562,7 @@
static int
odomainlist(uchar *w, int n, Otab *o, Req *q)
{
+ char val[256];
Ndbtuple *t;
int l, r;
char *s;
@@ -570,7 +571,9 @@
for(t = q->t; t != nil; t = t->entry){
if(strcmp(t->attr, o->q[0]) != 0)
continue;
- for(s = t->val; *s != 0; s++){
+ if(utf2idn(t->val, val, sizeof(val)) == nil)
+ continue;
+ for(s = val; *s != 0; s++){
for(l = 0; *s != 0 && *s != '.'; l++)
s++;
if(r+1+l > n)
@@ -578,6 +581,8 @@
w[r++] = l;
memmove(w+r, s-l, l);
r += l;
+ if(*s != '.')
+ break;
}
if(r >= n)
return -1;
--- a/sys/src/cmd/ip/dhcpd/dhcpd.c
+++ b/sys/src/cmd/ip/dhcpd/dhcpd.c
@@ -1584,7 +1584,7 @@
void
dnsnamesopt(Req *rp, int t, char *attr, Ndbtuple *nt)
{
- char *s;
+ char val[Maxstr], *s;
uchar *d;
int n, l;
@@ -1591,8 +1591,10 @@
for(; nt != nil; nt = nt->entry){
if(strcmp(nt->attr, attr) != 0)
continue;
+ if(utf2idn(nt->val, val, sizeof(val)) == nil)
+ continue;
d = &rp->p[2];
- for(s = nt->val; *s != 0; s++){
+ for(s = val; *s != 0; s++){
for(l = 0; *s != 0 && *s != '.'; l++)
s++;
if(l > 077)
@@ -1602,6 +1604,8 @@
return;
d[-l-1] = l;
memmove(d-l, s-l, l);
+ if(*s != '.')
+ break;
}
*d++ = 0;
n = d - &rp->p[2];
@@ -1610,7 +1614,7 @@
rp->p[0] = t;
rp->p[1] = n;
rp->p = d;
- op = seprint(op, oe, "%s(%s)", optname[t], nt->val);
+ op = seprint(op, oe, "%s(%s)", optname[t], val);
Skip:;
}
}
--- a/sys/src/cmd/ip/dhcpd/ndb.c
+++ b/sys/src/cmd/ip/dhcpd/ndb.c
@@ -305,7 +305,8 @@
for(nt = t; nt != nil; nt = nt->entry)
if(strcmp(nt->attr, "dom") == 0){
- strncpy(val, nt->val, len-1);
+ if(utf2idn(nt->val, val, len) == nil)
+ strncpy(val, nt->val, len-1);
val[len-1] = 0;
break;
}
--- a/sys/src/cmd/ip/ipconfig/main.c
+++ b/sys/src/cmd/ip/ipconfig/main.c
@@ -47,6 +47,9 @@
static void dounbind(void);
static void ndbconfig(void);
+static int Ufmt(Fmt*);
+#pragma varargck type "U" char*
+
void
usage(void)
{
@@ -61,12 +64,14 @@
init(void)
{
srand(truerand());
+
fmtinstall('H', encodefmt);
fmtinstall('E', eipfmt);
fmtinstall('I', eipfmt);
fmtinstall('M', eipfmt);
fmtinstall('V', eipfmt);
- nsec(); /* make sure time file is open before forking */
+ fmtinstall('U', Ufmt);
+ nsec(); /* make sure time file is open before forking */
conf.cfd = -1;
conf.rfd = -1;
@@ -193,7 +198,7 @@
if(p == nil || *p == 0)
p = sysname();
if(p != nil)
- strncpy(conf.hostname, p, sizeof conf.hostname-1);
+ utf2idn(p, conf.hostname, sizeof(conf.hostname));
}
/* defaults */
@@ -636,11 +641,12 @@
char *x;
for(; *s != 0; s = x+1){
- if((x = strchr(s, ' ')) == nil)
- x = strchr(s, 0);
- p = seprint(p, e, "%s=%.*s\n", attr, (int)(x - s), s);
- if(*x == 0)
+ if((x = strchr(s, ' ')) != nil)
+ *x = 0;
+ p = seprint(p, e, "%s=%U\n", attr, s);
+ if(x == nil)
break;
+ *x = ' ';
}
return p;
}
@@ -665,9 +671,9 @@
*np = 0;
}
if(*conf.hostname)
- p = seprint(p, e, "\tsys=%s\n", conf.hostname);
+ p = seprint(p, e, "\tsys=%U\n", conf.hostname);
if(*conf.domainname)
- p = seprint(p, e, "\tdom=%s.%s\n",
+ p = seprint(p, e, "\tdom=%U.%U\n",
conf.hostname, conf.domainname);
if(*conf.dnsdomain)
p = putnames(p, e, "\tdnsdomain", conf.dnsdomain);
@@ -967,6 +973,18 @@
return d - (de - nd);
}
+static int
+Ufmt(Fmt *f)
+{
+ char d[256], *s;
+
+ s = va_arg(f->args, char*);
+ if(idn2utf(s, d, sizeof(d)) != nil)
+ s = d;
+ fmtprint(f, "%s", s);
+ return 0;
+}
+
static Ndbtuple*
uniquent(Ndbtuple *t)
{
@@ -990,7 +1008,7 @@
ndb2conf(Ndb *db, uchar *myip)
{
int nattr;
- char *attrs[10], val[64];
+ char *attrs[10], val[256];
uchar ip[IPaddrlen];
Ndbtuple *t, *nt;
@@ -1021,7 +1039,9 @@
t = ndbipinfo(db, "ip", val, attrs, nattr);
for(nt = t; nt != nil; nt = nt->entry) {
if(strcmp(nt->attr, "dnsdomain") == 0) {
- addnames(conf.dnsdomain, nt->val, sizeof(conf.dnsdomain));
+ if(utf2idn(nt->val, val, sizeof(val)) == nil)
+ continue;
+ addnames(conf.dnsdomain, val, sizeof(conf.dnsdomain));
continue;
}
if(strcmp(nt->attr, "ipmask") == 0) {
--- a/sys/src/cmd/ndb/dns.h
+++ b/sys/src/cmd/ndb/dns.h
@@ -531,8 +531,4 @@
/* convM2DNS.c */
char* convM2DNS(uchar*, int, DNSmsg*, int*);
-/* idn.c */
-char* utf2idn(char *, char *, int);
-char* idn2utf(char *, char *, int);
-
#pragma varargck argpos dnslog 1
--- a/sys/src/cmd/ndb/idn.c
+++ /dev/null
@@ -1,262 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ip.h>
-#include "dns.h"
-
-enum {
- base = 36,
- tmin = 1,
- tmax = 26,
- skew = 38,
- damp = 700,
- initial_bias = 72,
- initial_n = 0x80,
-};
-
-static uint maxint = ~0;
-
-static uint
-decode_digit(uint cp)
-{
- if((cp - '0') < 10)
- return cp - ('0' - 26);
- if((cp - 'A') < 26)
- return cp - 'A';
- if((cp - 'a') < 26)
- return cp - 'a';
- return base;
-}
-
-static char
-encode_digit(uint d, int flag)
-{
- if(d < 26)
- return d + (flag ? 'A' : 'a');
- return d + ('0' - 26);
-}
-
-static uint
-adapt(uint delta, uint numpoints, int firsttime)
-{
- uint k;
-
- delta = firsttime ? delta / damp : delta >> 1;
- delta += delta / numpoints;
- for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
- delta /= base - tmin;
- return k + (base - tmin + 1) * delta / (delta + skew);
-}
-
-static int
-punyencode(uint input_length, Rune input[], uint max_out, char output[])
-{
- uint n, delta, h, b, out, bias, j, m, q, k, t;
-
- n = initial_n;
- delta = out = 0;
- bias = initial_bias;
-
- for (j = 0; j < input_length; ++j) {
- if ((uint)input[j] < 0x80) {
- if (max_out - out < 2)
- return -1;
- output[out++] = input[j];
- }
- }
-
- h = b = out;
-
- if (b > 0)
- output[out++] = '-';
-
- while (h < input_length) {
- for (m = maxint, j = 0; j < input_length; ++j) {
- if (input[j] >= n && input[j] < m)
- m = input[j];
- }
-
- if (m - n > (maxint - delta) / (h + 1))
- return -1;
-
- delta += (m - n) * (h + 1);
- n = m;
-
- for (j = 0; j < input_length; ++j) {
- if (input[j] < n) {
- if (++delta == 0)
- return -1;
- }
-
- if (input[j] == n) {
- for (q = delta, k = base;; k += base) {
- if (out >= max_out)
- return -1;
- if (k <= bias)
- t = tmin;
- else if (k >= bias + tmax)
- t = tmax;
- else
- t = k - bias;
- if (q < t)
- break;
- output[out++] = encode_digit(t + (q - t) % (base - t), 0);
- q = (q - t) / (base - t);
- }
- output[out++] = encode_digit(q, isupperrune(input[j]));
- bias = adapt(delta, h + 1, h == b);
- delta = 0;
- ++h;
- }
- }
-
- ++delta, ++n;
- }
-
- return (int)out;
-}
-
-static int
-punydecode(uint input_length, char input[], uint max_out, Rune output[])
-{
- uint n, out, i, bias, b, j, in, oldi, w, k, digit, t;
-
- n = initial_n;
- out = i = 0;
- bias = initial_bias;
-
- for (b = j = 0; j < input_length; ++j)
- if (input[j] == '-')
- b = j;
-
- if (b > max_out)
- return -1;
-
- for (j = 0; j < b; ++j) {
- if (input[j] & 0x80)
- return -1;
- output[out++] = input[j];
- }
-
- for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
- for (oldi = i, w = 1, k = base;; k += base) {
- if (in >= input_length)
- return -1;
- digit = decode_digit(input[in++]);
- if (digit >= base)
- return -1;
- if (digit > (maxint - i) / w)
- return -1;
- i += digit * w;
- if (k <= bias)
- t = tmin;
- else if (k >= bias + tmax)
- t = tmax;
- else
- t = k - bias;
- if (digit < t)
- break;
- if (w > maxint / (base - t))
- return -1;
- w *= (base - t);
- }
-
- bias = adapt(i - oldi, out + 1, oldi == 0);
-
- if (i / (out + 1) > maxint - n)
- return -1;
- n += i / (out + 1);
- i %= (out + 1);
-
- if (out >= max_out)
- return -1;
-
- memmove(output + i + 1, output + i, (out - i) * sizeof *output);
- if(((uint)input[in-1] - 'A') < 26)
- output[i++] = toupperrune(n);
- else
- output[i++] = tolowerrune(n);
- }
-
- return (int)out;
-}
-
-/*
- * convert punycode encoded internationalized
- * domain name to unicode string
- */
-char*
-idn2utf(char *name, char *buf, int nbuf)
-{
- char *dp, *de, *cp;
- Rune rb[Domlen], r;
- int nc, nr, n;
-
- cp = name;
- dp = buf;
- de = dp+nbuf-1;
- for(;;){
- nc = nr = 0;
- while(cp[nc] != 0){
- n = chartorune(&r, cp+nc);
- if(r == '.')
- break;
- rb[nr++] = r;
- nc += n;
- }
- if(cistrncmp(cp, "xn--", 4) == 0)
- if((nr = punydecode(nc-4, cp+4, nelem(rb), rb)) < 0)
- return nil;
- dp = seprint(dp, de, "%.*S", nr, rb);
- if(dp >= de)
- return nil;
- if(cp[nc] == 0)
- break;
- *dp++ = '.';
- cp += nc+1;
- }
- *dp = 0;
- return buf;
-}
-
-/*
- * convert unicode string to punycode
- * encoded internationalized domain name
- */
-char*
-utf2idn(char *name, char *buf, int nbuf)
-{
- char *dp, *de, *cp;
- Rune rb[Domlen], r;
- int nc, nr, n;
-
- dp = buf;
- de = dp+nbuf-1;
- cp = name;
- for(;;){
- nc = nr = 0;
- while(cp[nc] != 0 && nr < nelem(rb)){
- n = chartorune(&r, cp+nc);
- if(r == '.')
- break;
- rb[nr++] = r;
- nc += n;
- }
- if(nc == nr)
- dp = seprint(dp, de, "%.*s", nc, cp);
- else {
- dp = seprint(dp, de, "xn--");
- if((n = punyencode(nr, rb, de - dp, dp)) < 0)
- return nil;
- dp += n;
- }
- if(dp >= de)
- return nil;
- if(cp[nc] == 0)
- break;
- *dp++ = '.';
- cp += nc+1;
- }
- *dp = 0;
- return buf;
-}
-
--- a/sys/src/cmd/ndb/mkfile
+++ b/sys/src/cmd/ndb/mkfile
@@ -17,16 +17,16 @@
inform\
DNSOBJ = dns.$O dnudpserver.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O dnnotify.$O\
- dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+ dnarea.$O convM2DNS.$O convDNS2M.$O
DNSTCPOBJ = dnstcp.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O\
- dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+ dnarea.$O convM2DNS.$O convDNS2M.$O
DNSDEBUGOBJ = dnsdebug.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O\
- dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+ dnarea.$O convM2DNS.$O convDNS2M.$O
DNSGETIPOBJ = dnsgetip.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O\
- dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+ dnarea.$O convM2DNS.$O convDNS2M.$O
HFILES = dns.h /$objtype/lib/libndb.a
--- a/sys/src/cmd/webfs/fns.h
+++ b/sys/src/cmd/webfs/fns.h
@@ -25,10 +25,6 @@
int matchurl(Url *u, Url *s);
void freeurl(Url *u);
-/* idn */
-char* idn2utf(char *name, char *buf, int nbuf);
-char* utf2idn(char *name, char *buf, int nbuf);
-
/* buq */
int buread(Buq *q, void *v, int l);
int buwrite(Buq *q, void *v, int l);
--- a/sys/src/cmd/webfs/idn.c
+++ /dev/null
@@ -1,267 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-
-#include "dat.h"
-#include "fns.h"
-
-enum {
- base = 36,
- tmin = 1,
- tmax = 26,
- skew = 38,
- damp = 700,
- initial_bias = 72,
- initial_n = 0x80,
-};
-
-static uint maxint = ~0;
-
-static uint
-decode_digit(uint cp)
-{
- if((cp - '0') < 10)
- return cp - ('0' - 26);
- if((cp - 'A') < 26)
- return cp - 'A';
- if((cp - 'a') < 26)
- return cp - 'a';
- return base;
-}
-
-static char
-encode_digit(uint d, int flag)
-{
- if(d < 26)
- return d + (flag ? 'A' : 'a');
- return d + ('0' - 26);
-}
-
-static uint
-adapt(uint delta, uint numpoints, int firsttime)
-{
- uint k;
-
- delta = firsttime ? delta / damp : delta >> 1;
- delta += delta / numpoints;
- for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
- delta /= base - tmin;
- return k + (base - tmin + 1) * delta / (delta + skew);
-}
-
-static int
-punyencode(uint input_length, Rune input[], uint max_out, char output[])
-{
- uint n, delta, h, b, out, bias, j, m, q, k, t;
-
- n = initial_n;
- delta = out = 0;
- bias = initial_bias;
-
- for (j = 0; j < input_length; ++j) {
- if ((uint)input[j] < 0x80) {
- if (max_out - out < 2)
- return -1;
- output[out++] = input[j];
- }
- }
-
- h = b = out;
-
- if (b > 0)
- output[out++] = '-';
-
- while (h < input_length) {
- for (m = maxint, j = 0; j < input_length; ++j) {
- if (input[j] >= n && input[j] < m)
- m = input[j];
- }
-
- if (m - n > (maxint - delta) / (h + 1))
- return -1;
-
- delta += (m - n) * (h + 1);
- n = m;
-
- for (j = 0; j < input_length; ++j) {
- if (input[j] < n) {
- if (++delta == 0)
- return -1;
- }
-
- if (input[j] == n) {
- for (q = delta, k = base;; k += base) {
- if (out >= max_out)
- return -1;
- if (k <= bias)
- t = tmin;
- else if (k >= bias + tmax)
- t = tmax;
- else
- t = k - bias;
- if (q < t)
- break;
- output[out++] = encode_digit(t + (q - t) % (base - t), 0);
- q = (q - t) / (base - t);
- }
- output[out++] = encode_digit(q, isupperrune(input[j]));
- bias = adapt(delta, h + 1, h == b);
- delta = 0;
- ++h;
- }
- }
-
- ++delta, ++n;
- }
-
- return (int)out;
-}
-
-static int
-punydecode(uint input_length, char input[], uint max_out, Rune output[])
-{
- uint n, out, i, bias, b, j, in, oldi, w, k, digit, t;
-
- n = initial_n;
- out = i = 0;
- bias = initial_bias;
-
- for (b = j = 0; j < input_length; ++j)
- if (input[j] == '-')
- b = j;
-
- if (b > max_out)
- return -1;
-
- for (j = 0; j < b; ++j) {
- if (input[j] & 0x80)
- return -1;
- output[out++] = input[j];
- }
-
- for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
- for (oldi = i, w = 1, k = base;; k += base) {
- if (in >= input_length)
- return -1;
- digit = decode_digit(input[in++]);
- if (digit >= base)
- return -1;
- if (digit > (maxint - i) / w)
- return -1;
- i += digit * w;
- if (k <= bias)
- t = tmin;
- else if (k >= bias + tmax)
- t = tmax;
- else
- t = k - bias;
- if (digit < t)
- break;
- if (w > maxint / (base - t))
- return -1;
- w *= (base - t);
- }
-
- bias = adapt(i - oldi, out + 1, oldi == 0);
-
- if (i / (out + 1) > maxint - n)
- return -1;
- n += i / (out + 1);
- i %= (out + 1);
-
- if (out >= max_out)
- return -1;
-
- memmove(output + i + 1, output + i, (out - i) * sizeof *output);
- if(((uint)input[in-1] - 'A') < 26)
- output[i++] = toupperrune(n);
- else
- output[i++] = tolowerrune(n);
- }
-
- return (int)out;
-}
-
-/*
- * convert punycode encoded internationalized
- * domain name to unicode string
- */
-char*
-idn2utf(char *name, char *buf, int nbuf)
-{
- char *dp, *de, *cp;
- Rune rb[Domlen], r;
- int nc, nr, n;
-
- cp = name;
- dp = buf;
- de = dp+nbuf-1;
- for(;;){
- nc = nr = 0;
- while(cp[nc] != 0){
- n = chartorune(&r, cp+nc);
- if(r == '.')
- break;
- rb[nr++] = r;
- nc += n;
- }
- if(cistrncmp(cp, "xn--", 4) == 0)
- if((nr = punydecode(nc-4, cp+4, nelem(rb), rb)) < 0)
- return nil;
- dp = seprint(dp, de, "%.*S", nr, rb);
- if(dp >= de)
- return nil;
- if(cp[nc] == 0)
- break;
- *dp++ = '.';
- cp += nc+1;
- }
- *dp = 0;
- return buf;
-}
-
-/*
- * convert unicode string to punycode
- * encoded internationalized domain name
- */
-char*
-utf2idn(char *name, char *buf, int nbuf)
-{
- char *dp, *de, *cp;
- Rune rb[Domlen], r;
- int nc, nr, n;
-
- dp = buf;
- de = dp+nbuf-1;
- cp = name;
- for(;;){
- nc = nr = 0;
- while(cp[nc] != 0 && nr < nelem(rb)){
- n = chartorune(&r, cp+nc);
- if(r == '.')
- break;
- rb[nr++] = r;
- nc += n;
- }
- if(nc == nr)
- dp = seprint(dp, de, "%.*s", nc, cp);
- else {
- dp = seprint(dp, de, "xn--");
- if((n = punyencode(nr, rb, de - dp, dp)) < 0)
- return nil;
- dp += n;
- }
- if(dp >= de)
- return nil;
- if(cp[nc] == 0)
- break;
- *dp++ = '.';
- cp += nc+1;
- }
- *dp = 0;
- return buf;
-}
-
--- a/sys/src/cmd/webfs/mkfile
+++ b/sys/src/cmd/webfs/mkfile
@@ -3,6 +3,6 @@
TARG=webfs
HFILES=fns.h dat.h
-OFILES=sub.$O url.$O buq.$O http.$O fs.$O idn.$O
+OFILES=sub.$O url.$O buq.$O http.$O fs.$O
</sys/src/cmd/mkone
--- a/sys/src/cmd/webfs/url.c
+++ b/sys/src/cmd/webfs/url.c
@@ -73,15 +73,12 @@
int
Nfmt(Fmt *f)
{
- char *d, *s;
+ char d[Domlen], *s;
s = va_arg(f->args, char*);
- d = emalloc(Domlen);
- if(utf2idn(s, d, Domlen) == nil)
- d = s;
- fmtprint(f, "%s", d);
- if(d != s)
- free(d);
+ if(utf2idn(s, d, sizeof(d)) != nil)
+ s = d;
+ fmtprint(f, "%s", s);
return 0;
}
--- /dev/null
+++ b/sys/src/libc/9sys/idn.c
@@ -1,0 +1,262 @@
+#include <u.h>
+#include <libc.h>
+
+enum {
+ base = 36,
+ tmin = 1,
+ tmax = 26,
+ skew = 38,
+ damp = 700,
+ initial_bias = 72,
+ initial_n = 0x80,
+
+ Domlen = 256,
+};
+
+static uint maxint = ~0;
+
+static uint
+decode_digit(uint cp)
+{
+ if((cp - '0') < 10)
+ return cp - ('0' - 26);
+ if((cp - 'A') < 26)
+ return cp - 'A';
+ if((cp - 'a') < 26)
+ return cp - 'a';
+ return base;
+}
+
+static char
+encode_digit(uint d, int flag)
+{
+ if(d < 26)
+ return d + (flag ? 'A' : 'a');
+ return d + ('0' - 26);
+}
+
+static uint
+adapt(uint delta, uint numpoints, int firsttime)
+{
+ uint k;
+
+ delta = firsttime ? delta / damp : delta >> 1;
+ delta += delta / numpoints;
+ for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
+ delta /= base - tmin;
+ return k + (base - tmin + 1) * delta / (delta + skew);
+}
+
+static int
+punyencode(uint input_length, Rune input[], uint max_out, char output[])
+{
+ uint n, delta, h, b, out, bias, j, m, q, k, t;
+
+ n = initial_n;
+ delta = out = 0;
+ bias = initial_bias;
+
+ for (j = 0; j < input_length; ++j) {
+ if ((uint)input[j] < 0x80) {
+ if (max_out - out < 2)
+ return -1;
+ output[out++] = input[j];
+ }
+ }
+
+ h = b = out;
+
+ if (b > 0)
+ output[out++] = '-';
+
+ while (h < input_length) {
+ for (m = maxint, j = 0; j < input_length; ++j) {
+ if (input[j] >= n && input[j] < m)
+ m = input[j];
+ }
+
+ if (m - n > (maxint - delta) / (h + 1))
+ return -1;
+
+ delta += (m - n) * (h + 1);
+ n = m;
+
+ for (j = 0; j < input_length; ++j) {
+ if (input[j] < n) {
+ if (++delta == 0)
+ return -1;
+ }
+
+ if (input[j] == n) {
+ for (q = delta, k = base;; k += base) {
+ if (out >= max_out)
+ return -1;
+ if (k <= bias)
+ t = tmin;
+ else if (k >= bias + tmax)
+ t = tmax;
+ else
+ t = k - bias;
+ if (q < t)
+ break;
+ output[out++] = encode_digit(t + (q - t) % (base - t), 0);
+ q = (q - t) / (base - t);
+ }
+ output[out++] = encode_digit(q, isupperrune(input[j]));
+ bias = adapt(delta, h + 1, h == b);
+ delta = 0;
+ ++h;
+ }
+ }
+
+ ++delta, ++n;
+ }
+
+ return (int)out;
+}
+
+static int
+punydecode(uint input_length, char input[], uint max_out, Rune output[])
+{
+ uint n, out, i, bias, b, j, in, oldi, w, k, digit, t;
+
+ n = initial_n;
+ out = i = 0;
+ bias = initial_bias;
+
+ for (b = j = 0; j < input_length; ++j)
+ if (input[j] == '-')
+ b = j;
+
+ if (b > max_out)
+ return -1;
+
+ for (j = 0; j < b; ++j) {
+ if (input[j] & 0x80)
+ return -1;
+ output[out++] = input[j];
+ }
+
+ for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
+ for (oldi = i, w = 1, k = base;; k += base) {
+ if (in >= input_length)
+ return -1;
+ digit = decode_digit(input[in++]);
+ if (digit >= base)
+ return -1;
+ if (digit > (maxint - i) / w)
+ return -1;
+ i += digit * w;
+ if (k <= bias)
+ t = tmin;
+ else if (k >= bias + tmax)
+ t = tmax;
+ else
+ t = k - bias;
+ if (digit < t)
+ break;
+ if (w > maxint / (base - t))
+ return -1;
+ w *= (base - t);
+ }
+
+ bias = adapt(i - oldi, out + 1, oldi == 0);
+
+ if (i / (out + 1) > maxint - n)
+ return -1;
+ n += i / (out + 1);
+ i %= (out + 1);
+
+ if (out >= max_out)
+ return -1;
+
+ memmove(output + i + 1, output + i, (out - i) * sizeof *output);
+ if(((uint)input[in-1] - 'A') < 26)
+ output[i++] = toupperrune(n);
+ else
+ output[i++] = tolowerrune(n);
+ }
+
+ return (int)out;
+}
+
+/*
+ * convert punycode encoded internationalized
+ * domain name to unicode string
+ */
+char*
+idn2utf(char *name, char *buf, int nbuf)
+{
+ char *dp, *de, *cp;
+ Rune rb[Domlen], r;
+ int nc, nr, n;
+
+ cp = name;
+ dp = buf;
+ de = dp+nbuf-1;
+ for(;;){
+ nc = nr = 0;
+ while(cp[nc] != 0){
+ n = chartorune(&r, cp+nc);
+ if(r == '.')
+ break;
+ rb[nr++] = r;
+ nc += n;
+ }
+ if(cistrncmp(cp, "xn--", 4) == 0)
+ if((nr = punydecode(nc-4, cp+4, nelem(rb), rb)) < 0)
+ return nil;
+ dp = seprint(dp, de, "%.*S", nr, rb);
+ if(dp >= de)
+ return nil;
+ if(cp[nc] == 0)
+ break;
+ *dp++ = '.';
+ cp += nc+1;
+ }
+ *dp = 0;
+ return buf;
+}
+
+/*
+ * convert unicode string to punycode
+ * encoded internationalized domain name
+ */
+char*
+utf2idn(char *name, char *buf, int nbuf)
+{
+ char *dp, *de, *cp;
+ Rune rb[Domlen], r;
+ int nc, nr, n;
+
+ dp = buf;
+ de = dp+nbuf-1;
+ cp = name;
+ for(;;){
+ nc = nr = 0;
+ while(cp[nc] != 0 && nr < nelem(rb)){
+ n = chartorune(&r, cp+nc);
+ if(r == '.')
+ break;
+ rb[nr++] = r;
+ nc += n;
+ }
+ if(nc == nr)
+ dp = seprint(dp, de, "%.*s", nc, cp);
+ else {
+ dp = seprint(dp, de, "xn--");
+ if((n = punyencode(nr, rb, de - dp, dp)) < 0)
+ return nil;
+ dp += n;
+ }
+ if(dp >= de)
+ return nil;
+ if(cp[nc] == 0)
+ break;
+ *dp++ = '.';
+ cp += nc+1;
+ }
+ *dp = 0;
+ return buf;
+}
+
--- a/sys/src/libc/9sys/mkfile
+++ b/sys/src/libc/9sys/mkfile
@@ -25,6 +25,7 @@
getpid.$O\
getppid.$O\
getwd.$O\
+ idn.$O\
iounit.$O\
nsec.$O\
nulldir.$O\