summaryrefslogtreecommitdiff
path: root/src/lib9
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib9')
-rw-r--r--src/lib9/Makefile126
-rw-r--r--src/lib9/_exits.c35
-rw-r--r--src/lib9/_p9dir.c315
-rw-r--r--src/lib9/argv0.c34
-rw-r--r--src/lib9/atoi.c45
-rw-r--r--src/lib9/await.c179
-rw-r--r--src/lib9/cleanname.c78
-rw-r--r--src/lib9/create.c99
-rw-r--r--src/lib9/dirfstat.c54
-rw-r--r--src/lib9/dirfwstat.c78
-rw-r--r--src/lib9/dirstat.c57
-rw-r--r--src/lib9/dirwstat.c43
-rw-r--r--src/lib9/dup.c36
-rw-r--r--src/lib9/errstr.c106
-rw-r--r--src/lib9/exec.c33
-rw-r--r--src/lib9/execl.c53
-rw-r--r--src/lib9/exitcode.c34
-rw-r--r--src/lib9/fmt/charstod.c88
-rw-r--r--src/lib9/fmt/dofmt.c629
-rw-r--r--src/lib9/fmt/dorfmt.c65
-rw-r--r--src/lib9/fmt/errfmt.c30
-rw-r--r--src/lib9/fmt/fltfmt.c677
-rw-r--r--src/lib9/fmt/fmt.c235
-rw-r--r--src/lib9/fmt/fmtdef.h119
-rw-r--r--src/lib9/fmt/fmtfd.c51
-rw-r--r--src/lib9/fmt/fmtfdflush.c37
-rw-r--r--src/lib9/fmt/fmtlocale.c69
-rw-r--r--src/lib9/fmt/fmtlock.c31
-rw-r--r--src/lib9/fmt/fmtnull.c48
-rw-r--r--src/lib9/fmt/fmtprint.c51
-rw-r--r--src/lib9/fmt/fmtquote.c274
-rw-r--r--src/lib9/fmt/fmtrune.c43
-rw-r--r--src/lib9/fmt/fmtstr.c31
-rw-r--r--src/lib9/fmt/fmtvprint.c52
-rw-r--r--src/lib9/fmt/fprint.c33
-rw-r--r--src/lib9/fmt/nan64.c93
-rw-r--r--src/lib9/fmt/pow10.c60
-rw-r--r--src/lib9/fmt/print.c33
-rw-r--r--src/lib9/fmt/seprint.c33
-rw-r--r--src/lib9/fmt/smprint.c33
-rw-r--r--src/lib9/fmt/snprint.c34
-rw-r--r--src/lib9/fmt/sprint.c45
-rw-r--r--src/lib9/fmt/test.c65
-rw-r--r--src/lib9/fmt/vfprint.c37
-rw-r--r--src/lib9/fmt/vseprint.c44
-rw-r--r--src/lib9/fmt/vsmprint.c87
-rw-r--r--src/lib9/fmt/vsnprint.c43
-rw-r--r--src/lib9/fmtlock2.c38
-rw-r--r--src/lib9/fork.c46
-rw-r--r--src/lib9/getenv.c50
-rw-r--r--src/lib9/getfields.c62
-rw-r--r--src/lib9/getuser.c41
-rw-r--r--src/lib9/getwd.c34
-rw-r--r--src/lib9/jmp.c42
-rw-r--r--src/lib9/main.c38
-rw-r--r--src/lib9/nan.c52
-rw-r--r--src/lib9/notify.c297
-rw-r--r--src/lib9/nulldir.c35
-rw-r--r--src/lib9/open.c87
-rw-r--r--src/lib9/pipe.c39
-rw-r--r--src/lib9/readn.c47
-rw-r--r--src/lib9/rfork.c153
-rw-r--r--src/lib9/seek.c33
-rw-r--r--src/lib9/strecpy.c42
-rw-r--r--src/lib9/sysfatal.c47
-rw-r--r--src/lib9/tokenize.c132
-rw-r--r--src/lib9/utf/rune.c177
-rw-r--r--src/lib9/utf/runetype.c1151
-rw-r--r--src/lib9/utf/utfdef.h47
-rw-r--r--src/lib9/utf/utfecpy.c37
-rw-r--r--src/lib9/utf/utflen.c37
-rw-r--r--src/lib9/utf/utfnlen.c41
-rw-r--r--src/lib9/utf/utfrrune.c45
-rw-r--r--src/lib9/utf/utfrune.c44
-rw-r--r--src/lib9/utf/utfutf.c41
75 files changed, 7510 insertions, 0 deletions
diff --git a/src/lib9/Makefile b/src/lib9/Makefile
new file mode 100644
index 000000000..12b72f01e
--- /dev/null
+++ b/src/lib9/Makefile
@@ -0,0 +1,126 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../Make.conf
+
+LIB=lib9.a
+
+NUM=\
+ charstod.$O\
+ pow10.$O\
+
+# Could add fmt/errfmt, but we want to pick it up from ./errstr.c instead.
+FMTOFILES=\
+ dofmt.$O\
+ fltfmt.$O\
+ fmt.$O\
+ fmtfd.$O\
+ fmtfdflush.$O\
+ fmtlocale.$O\
+ fmtlock2.$O\
+ fmtnull.$O\
+ fmtprint.$O\
+ fmtquote.$O\
+ fmtrune.$O\
+ fmtstr.$O\
+ fmtvprint.$O\
+ fprint.$O\
+ nan64.$O\
+ print.$O\
+ seprint.$O\
+ smprint.$O\
+ snprint.$O\
+ sprint.$O\
+ strtod.$O\
+ vfprint.$O\
+ vseprint.$O\
+ vsmprint.$O\
+ vsnprint.$O\
+ $(NUM)\
+
+UTFOFILES=\
+ rune.$O\
+ utfecpy.$O\
+ utflen.$O\
+ utfnlen.$O\
+ utfrrune.$O\
+ utfrune.$O\
+ utfutf.$O\
+ runetype.$O\
+
+LIB9OFILES=\
+ _p9dir.$O\
+ _exits.$O\
+ argv0.$O\
+ atoi.$O\
+ await.$O\
+ cleanname.$O\
+ create.$O\
+ dirfstat.$O\
+ dirfwstat.$O\
+ dirstat.$O\
+ dirwstat.$O\
+ dup.$O\
+ errstr.$O\
+ exec.$O\
+ execl.$O\
+ exitcode.$O\
+ exits.$O\
+ getenv.$O\
+ getfields.$O\
+ getuser.$O\
+ getwd.$O\
+ jmp.$O\
+ main.$O\
+ nan.$O\
+ notify.$O\
+ nulldir.$O\
+ open.$O\
+ pipe.$O\
+ readn.$O\
+ rfork.$O\
+ seek.$O\
+ strecpy.$O\
+ sysfatal.$O\
+ time.$O\
+ tokenize.$O\
+
+OFILES=\
+ $(LIB9OFILES)\
+ $(FMTOFILES)\
+ $(UTFOFILES)\
+
+HFILES=\
+ $(GOROOT)/include/u.h\
+ $(GOROOT)/include/libc.h\
+
+install: $(LIB)
+ cp $(LIB) $(GOROOT)/lib
+
+$(LIB): $(OFILES)
+ ar rsc $(LIB) $(OFILES)
+
+%.$O: fmt/%.c
+ $(CC) -c $(CFLAGS) -DPLAN9PORT -Ifmt $<
+
+%.$O: utf/%.c
+ $(CC) -c $(CFLAGS) $<
+
+clean:
+ rm -f *.$O *.6 6.out $(LIB)
+
+nuke: clean
+ rm -f $(GOROOT)/lib/$(LIB)
+
+#XLIB=$PLAN9/lib/$LIB
+
+#testfmt: testfmt.$O $XLIB
+# $LD -o $target testfmt.$O
+
+#testfltfmt: testfltfmt.$O $XLIB
+# $LD -o $target testfltfmt.$O
+
+#testprint: testprint.$O $XLIB
+# $LD -o $target testprint.$O
+
diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c
new file mode 100644
index 000000000..ea8ea74e2
--- /dev/null
+++ b/src/lib9/_exits.c
@@ -0,0 +1,35 @@
+/*
+Plan 9 from User Space src/lib9/_exits.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void
+_exits(char *s)
+{
+ if(s == 0 || *s == 0)
+ _exit(0);
+ _exit(exitcode(s));
+}
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
new file mode 100644
index 000000000..1c1aa6582
--- /dev/null
+++ b/src/lib9/_p9dir.c
@@ -0,0 +1,315 @@
+/*
+Plan 9 from User Space src/lib9/_p9dir.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_p9dir.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(__FreeBSD__)
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+#endif
+
+#if defined(__OpenBSD__)
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+#define _HAVEDISKLABEL
+static int diskdev[] = {
+ 151, /* aacd */
+ 116, /* ad */
+ 157, /* ar */
+ 118, /* afd */
+ 133, /* amrd */
+ 13, /* da */
+ 102, /* fla */
+ 109, /* idad */
+ 95, /* md */
+ 131, /* mlxd */
+ 168, /* pst */
+ 147, /* twed */
+ 43, /* vn */
+ 3, /* wd */
+ 87, /* wfd */
+ 4, /* da on FreeBSD 5 */
+};
+static int
+isdisk(struct stat *st)
+{
+ int i, dev;
+
+ if(!S_ISCHR(st->st_mode))
+ return 0;
+ dev = major(st->st_rdev);
+ for(i=0; i<nelem(diskdev); i++)
+ if(diskdev[i] == dev)
+ return 1;
+ return 0;
+}
+#endif
+
+#if defined(__FreeBSD__) /* maybe OpenBSD too? */
+char *diskdev[] = {
+ "aacd",
+ "ad",
+ "ar",
+ "afd",
+ "amrd",
+ "da",
+ "fla",
+ "idad",
+ "md",
+ "mlxd",
+ "pst",
+ "twed",
+ "vn",
+ "wd",
+ "wfd",
+ "da",
+};
+static int
+isdisk(struct stat *st)
+{
+ char *name;
+ int i, len;
+
+ if(!S_ISCHR(st->st_mode))
+ return 0;
+ name = devname(st->st_rdev, S_IFCHR);
+ for(i=0; i<nelem(diskdev); i++){
+ len = strlen(diskdev[i]);
+ if(strncmp(diskdev[i], name, len) == 0 && isdigit((uchar)name[len]))
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+
+#if defined(__linux__)
+#include <linux/hdreg.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#undef major
+#define major(dev) ((int)(((dev) >> 8) & 0xff))
+static vlong
+disksize(int fd, int dev)
+{
+ u64int u64;
+ long l;
+ struct hd_geometry geo;
+
+ memset(&geo, 0, sizeof geo);
+ l = 0;
+ u64 = 0;
+#ifdef BLKGETSIZE64
+ if(ioctl(fd, BLKGETSIZE64, &u64) >= 0)
+ return u64;
+#endif
+ if(ioctl(fd, BLKGETSIZE, &l) >= 0)
+ return l*512;
+ if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
+ return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
+ return 0;
+}
+#define _HAVEDISKSIZE
+#endif
+
+#if !defined(__linux__) && !defined(__sun__)
+#define _HAVESTGEN
+#endif
+
+int _p9usepwlibrary = 1;
+/*
+ * Caching the last group and passwd looked up is
+ * a significant win (stupidly enough) on most systems.
+ * It's not safe for threaded programs, but neither is using
+ * getpwnam in the first place, so I'm not too worried.
+ */
+int
+_p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
+{
+ char *s;
+ char tmp[20];
+ static struct group *g;
+ static struct passwd *p;
+ static int gid, uid;
+ int sz, fd;
+
+ fd = -1;
+ USED(fd);
+ sz = 0;
+ if(d)
+ memset(d, 0, sizeof *d);
+
+ /* name */
+ s = strrchr(name, '/');
+ if(s)
+ s++;
+ if(!s || !*s)
+ s = name;
+ if(*s == '/')
+ s++;
+ if(*s == 0)
+ s = "/";
+ if(d){
+ if(*str + strlen(s)+1 > estr)
+ d->name = "oops";
+ else{
+ strcpy(*str, s);
+ d->name = *str;
+ *str += strlen(*str)+1;
+ }
+ }
+ sz += strlen(s)+1;
+
+ /* user */
+ if(p && st->st_uid == uid && p->pw_uid == uid)
+ ;
+ else if(_p9usepwlibrary){
+ p = getpwuid(st->st_uid);
+ uid = st->st_uid;
+ }
+ if(p == nil || st->st_uid != uid || p->pw_uid != uid){
+ snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
+ s = tmp;
+ }else
+ s = p->pw_name;
+ sz += strlen(s)+1;
+ if(d){
+ if(*str+strlen(s)+1 > estr)
+ d->uid = "oops";
+ else{
+ strcpy(*str, s);
+ d->uid = *str;
+ *str += strlen(*str)+1;
+ }
+ }
+
+ /* group */
+ if(g && st->st_gid == gid && g->gr_gid == gid)
+ ;
+ else if(_p9usepwlibrary){
+ g = getgrgid(st->st_gid);
+ gid = st->st_gid;
+ }
+ if(g == nil || st->st_gid != gid || g->gr_gid != gid){
+ snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
+ s = tmp;
+ }else
+ s = g->gr_name;
+ sz += strlen(s)+1;
+ if(d){
+ if(*str + strlen(s)+1 > estr)
+ d->gid = "oops";
+ else{
+ strcpy(*str, s);
+ d->gid = *str;
+ *str += strlen(*str)+1;
+ }
+ }
+
+ if(d){
+ d->type = 'M';
+
+ d->muid = "";
+ d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
+#ifdef _HAVESTGEN
+ d->qid.vers = st->st_gen;
+#endif
+ if(d->qid.vers == 0)
+ d->qid.vers = st->st_mtime + st->st_ctime;
+ d->mode = st->st_mode&0777;
+ d->atime = st->st_atime;
+ d->mtime = st->st_mtime;
+ d->length = st->st_size;
+
+ if(S_ISDIR(st->st_mode)){
+ d->length = 0;
+ d->mode |= DMDIR;
+ d->qid.type = QTDIR;
+ }
+ if(S_ISLNK(lst->st_mode)) /* yes, lst not st */
+ d->mode |= DMSYMLINK;
+ if(S_ISFIFO(st->st_mode))
+ d->mode |= DMNAMEDPIPE;
+ if(S_ISSOCK(st->st_mode))
+ d->mode |= DMSOCKET;
+ if(S_ISBLK(st->st_mode)){
+ d->mode |= DMDEVICE;
+ d->qid.path = ('b'<<16)|st->st_rdev;
+ }
+ if(S_ISCHR(st->st_mode)){
+ d->mode |= DMDEVICE;
+ d->qid.path = ('c'<<16)|st->st_rdev;
+ }
+ /* fetch real size for disks */
+#ifdef _HAVEDISKSIZE
+ if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
+ d->length = disksize(fd, major(st->st_dev));
+ close(fd);
+ }
+#endif
+#if defined(DIOCGMEDIASIZE)
+ if(isdisk(st)){
+ int fd;
+ off_t mediasize;
+
+ if((fd = open(name, O_RDONLY)) >= 0){
+ if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
+ d->length = mediasize;
+ close(fd);
+ }
+ }
+#elif defined(_HAVEDISKLABEL)
+ if(isdisk(st)){
+ int fd, n;
+ struct disklabel lab;
+
+ if((fd = open(name, O_RDONLY)) < 0)
+ goto nosize;
+ if(ioctl(fd, DIOCGDINFO, &lab) < 0)
+ goto nosize;
+ n = minor(st->st_rdev)&7;
+ if(n >= lab.d_npartitions)
+ goto nosize;
+
+ d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
+
+ nosize:
+ if(fd >= 0)
+ close(fd);
+ }
+#endif
+ }
+
+ return sz;
+}
+
diff --git a/src/lib9/argv0.c b/src/lib9/argv0.c
new file mode 100644
index 000000000..f109efde0
--- /dev/null
+++ b/src/lib9/argv0.c
@@ -0,0 +1,34 @@
+/*
+Plan 9 from User Space src/lib9/argv0.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/argv0.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <lib9.h>
+
+char *argv0;
+
+/*
+ * Mac OS can't deal with files that only declare data.
+ * ARGBEGIN mentions this function so that this file gets pulled in.
+ */
+void __fixargv0(void) { }
diff --git a/src/lib9/atoi.c b/src/lib9/atoi.c
new file mode 100644
index 000000000..37a178280
--- /dev/null
+++ b/src/lib9/atoi.c
@@ -0,0 +1,45 @@
+/*
+Plan 9 from User Space src/lib9/ato*.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/atoi.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+int
+atoi(char *s)
+{
+ return strtol(s, 0, 0);
+}
+
+long
+atol(char *s)
+{
+ return strtol(s, 0, 0);
+}
+
+vlong
+atoll(char *s)
+{
+ return strtoll(s, 0, 0);
+}
diff --git a/src/lib9/await.c b/src/lib9/await.c
new file mode 100644
index 000000000..90be598a1
--- /dev/null
+++ b/src/lib9/await.c
@@ -0,0 +1,179 @@
+/*
+Plan 9 from User Space src/lib9/await.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/await.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+Portions Copyright 2009 The Go Authors. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifndef WCOREDUMP /* not on Mac OS X Tiger */
+#define WCOREDUMP(status) 0
+#endif
+
+static struct {
+ int sig;
+ char *str;
+} tab[] = {
+ SIGHUP, "hangup",
+ SIGINT, "interrupt",
+ SIGQUIT, "quit",
+ SIGILL, "sys: illegal instruction",
+ SIGTRAP, "sys: breakpoint",
+ SIGABRT, "sys: abort",
+#ifdef SIGEMT
+ SIGEMT, "sys: emulate instruction executed",
+#endif
+ SIGFPE, "sys: fp: trap",
+ SIGKILL, "sys: kill",
+ SIGBUS, "sys: bus error",
+ SIGSEGV, "sys: segmentation violation",
+ SIGALRM, "alarm",
+ SIGTERM, "kill",
+ SIGURG, "sys: urgent condition on socket",
+ SIGSTOP, "sys: stop",
+ SIGTSTP, "sys: tstp",
+ SIGCONT, "sys: cont",
+ SIGCHLD, "sys: child",
+ SIGTTIN, "sys: ttin",
+ SIGTTOU, "sys: ttou",
+#ifdef SIGIO /* not on Mac OS X Tiger */
+ SIGIO, "sys: i/o possible on fd",
+#endif
+ SIGXCPU, "sys: cpu time limit exceeded",
+ SIGXFSZ, "sys: file size limit exceeded",
+ SIGVTALRM, "sys: virtual time alarm",
+ SIGPROF, "sys: profiling timer alarm",
+#ifdef SIGWINCH /* not on Mac OS X Tiger */
+ SIGWINCH, "sys: window size change",
+#endif
+#ifdef SIGINFO
+ SIGINFO, "sys: status request",
+#endif
+ SIGUSR1, "sys: usr1",
+ SIGUSR2, "sys: usr2",
+ SIGPIPE, "sys: write on closed pipe",
+};
+
+char*
+_p9sigstr(int sig, char *tmp)
+{
+ int i;
+
+ for(i=0; i<nelem(tab); i++)
+ if(tab[i].sig == sig)
+ return tab[i].str;
+ if(tmp == nil)
+ return nil;
+ sprint(tmp, "sys: signal %d", sig);
+ return tmp;
+}
+
+int
+_p9strsig(char *s)
+{
+ int i;
+
+ for(i=0; i<nelem(tab); i++)
+ if(strcmp(s, tab[i].str) == 0)
+ return tab[i].sig;
+ return 0;
+}
+
+static Waitmsg*
+_wait(int pid4, int opt)
+{
+ int pid, status, cd;
+ struct rusage ru;
+ char tmp[64];
+ ulong u, s;
+ Waitmsg *w;
+
+ w = malloc(sizeof *w + 200);
+ if(w == nil)
+ return nil;
+ memset(w, 0, sizeof *w);
+ w->msg = (char*)&w[1];
+
+ for(;;){
+ /* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
+ if(pid4 == -1)
+ pid = wait3(&status, opt, &ru);
+ else
+ pid = wait4(pid4, &status, opt, &ru);
+ if(pid <= 0) {
+ free(w);
+ return nil;
+ }
+ u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
+ s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
+ w->pid = pid;
+ w->time[0] = u;
+ w->time[1] = s;
+ w->time[2] = u+s;
+ if(WIFEXITED(status)){
+ if(status)
+ sprint(w->msg, "%d", status);
+ return w;
+ }
+ if(WIFSIGNALED(status)){
+ cd = WCOREDUMP(status);
+ sprint(w->msg, "signal: %s", _p9sigstr(WTERMSIG(status), tmp));
+ if(cd)
+ strcat(w->msg, " (core dumped)");
+ return w;
+ }
+ }
+}
+
+Waitmsg*
+p9wait(void)
+{
+ return _wait(-1, 0);
+}
+
+Waitmsg*
+p9waitfor(int pid)
+{
+ return _wait(pid, 0);
+}
+
+Waitmsg*
+p9waitnohang(void)
+{
+ return _wait(-1, WNOHANG);
+}
+
+int
+p9waitpid(void)
+{
+ int status;
+ return wait(&status);
+}
diff --git a/src/lib9/cleanname.c b/src/lib9/cleanname.c
new file mode 100644
index 000000000..fee40388f
--- /dev/null
+++ b/src/lib9/cleanname.c
@@ -0,0 +1,78 @@
+/*
+Inferno libkern/cleanname.c
+http://code.google.com/p/inferno-os/source/browse/libkern/cleanname.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x) ((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+ char *p, *q, *dotdot;
+ int rooted;
+
+ rooted = name[0] == '/';
+
+ /*
+ * invariants:
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ * dotdot points just past the point where .. cannot backtrack
+ * any further (no slash).
+ */
+ p = q = dotdot = name+rooted;
+ while(*p) {
+ if(p[0] == '/') /* null element */
+ p++;
+ else if(p[0] == '.' && SEP(p[1]))
+ p += 1; /* don't count the separator in case it is nul */
+ else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+ p += 2;
+ if(q > dotdot) { /* can backtrack */
+ while(--q > dotdot && *q != '/')
+ ;
+ } else if(!rooted) { /* /.. is / but ./../ is .. */
+ if(q != name)
+ *q++ = '/';
+ *q++ = '.';
+ *q++ = '.';
+ dotdot = q;
+ }
+ } else { /* real path element */
+ if(q != name+rooted)
+ *q++ = '/';
+ while((*q = *p) != '/' && *q != 0)
+ p++, q++;
+ }
+ }
+ if(q == name) /* empty string is really ``.'' */
+ *q++ = '.';
+ *q = '\0';
+ return name;
+}
diff --git a/src/lib9/create.c b/src/lib9/create.c
new file mode 100644
index 000000000..8e5cbc360
--- /dev/null
+++ b/src/lib9/create.c
@@ -0,0 +1,99 @@
+/*
+Plan 9 from User Space src/lib9/create.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/create.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#define _GNU_SOURCE /* for Linux O_DIRECT */
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <sys/file.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libc.h>
+#include <sys/stat.h>
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+int
+p9create(char *path, int mode, ulong perm)
+{
+ int fd, cexec, umode, rclose, lock, rdwr;
+ struct flock fl;
+
+ rdwr = mode&3;
+ lock = mode&OLOCK;
+ cexec = mode&OCEXEC;
+ rclose = mode&ORCLOSE;
+ mode &= ~(ORCLOSE|OCEXEC|OLOCK);
+
+ /* XXX should get mode mask right? */
+ fd = -1;
+ if(perm&DMDIR){
+ if(mode != OREAD){
+ werrstr("bad mode in directory create");
+ goto out;
+ }
+ if(mkdir(path, perm&0777) < 0)
+ goto out;
+ fd = open(path, O_RDONLY);
+ }else{
+ umode = (mode&3)|O_CREAT|O_TRUNC;
+ mode &= ~(3|OTRUNC);
+ if(mode&ODIRECT){
+ umode |= O_DIRECT;
+ mode &= ~ODIRECT;
+ }
+ if(mode&OEXCL){
+ umode |= O_EXCL;
+ mode &= ~OEXCL;
+ }
+ if(mode&OAPPEND){
+ umode |= O_APPEND;
+ mode &= ~OAPPEND;
+ }
+ if(mode){
+ werrstr("unsupported mode in create");
+ goto out;
+ }
+ fd = open(path, umode, perm);
+ }
+out:
+ if(fd >= 0){
+ if(lock){
+ fl.l_type = (rdwr==OREAD) ? F_RDLCK : F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ if(fcntl(fd, F_SETLK, &fl) < 0){
+ close(fd);
+ werrstr("lock: %r");
+ return -1;
+ }
+ }
+ if(cexec)
+ fcntl(fd, F_SETFL, FD_CLOEXEC);
+ if(rclose)
+ remove(path);
+ }
+ return fd;
+}
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
new file mode 100644
index 000000000..17fe10aee
--- /dev/null
+++ b/src/lib9/dirfstat.c
@@ -0,0 +1,54 @@
+/*
+Plan 9 from User Space src/lib9/dirfstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirfstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/stat.h>
+
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
+
+Dir*
+dirfstat(int fd)
+{
+ struct stat st;
+ int nstr;
+ Dir *d;
+ char *str, tmp[100];
+
+ if(fstat(fd, &st) < 0)
+ return nil;
+
+ snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
+ nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
+ d = malloc(sizeof(Dir)+nstr);
+ if(d == nil)
+ return nil;
+ memset(d, 0, sizeof(Dir)+nstr);
+ str = (char*)&d[1];
+ _p9dir(&st, &st, tmp, d, &str, str+nstr);
+ return d;
+}
+
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
new file mode 100644
index 000000000..657a98df0
--- /dev/null
+++ b/src/lib9/dirfwstat.c
@@ -0,0 +1,78 @@
+/*
+Plan 9 from User Space src/lib9/dirfwstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirfwstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
+/* do nothing -- futimes exists and is fine */
+
+#elif defined(__SunOS5_9__)
+/* use futimesat */
+static int
+futimes(int fd, struct timeval *tv)
+{
+ return futimesat(fd, 0, tv);
+}
+
+#else
+/* provide dummy */
+/* rename just in case -- linux provides an unusable one */
+#undef futimes
+#define futimes myfutimes
+static int
+futimes(int fd, struct timeval *tv)
+{
+ werrstr("futimes not available");
+ return -1;
+}
+
+#endif
+
+int
+dirfwstat(int fd, Dir *dir)
+{
+ int ret;
+ struct timeval tv[2];
+
+ ret = 0;
+ if(~dir->mode != 0){
+ if(fchmod(fd, dir->mode) < 0)
+ ret = -1;
+ }
+ if(~dir->mtime != 0){
+ tv[0].tv_sec = dir->mtime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = dir->mtime;
+ tv[1].tv_usec = 0;
+ if(futimes(fd, tv) < 0)
+ ret = -1;
+ }
+ return ret;
+}
+
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
new file mode 100644
index 000000000..5cb6790bc
--- /dev/null
+++ b/src/lib9/dirstat.c
@@ -0,0 +1,57 @@
+/*
+Plan 9 from User Space src/lib9/dirstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/stat.h>
+
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
+
+Dir*
+dirstat(char *file)
+{
+ struct stat lst;
+ struct stat st;
+ int nstr;
+ Dir *d;
+ char *str;
+
+ if(lstat(file, &lst) < 0)
+ return nil;
+ st = lst;
+ if((lst.st_mode&S_IFMT) == S_IFLNK)
+ stat(file, &st);
+
+ nstr = _p9dir(&lst, &st, file, nil, nil, nil);
+ d = malloc(sizeof(Dir)+nstr);
+ if(d == nil)
+ return nil;
+ memset(d, 0, sizeof(Dir)+nstr);
+ str = (char*)&d[1];
+ _p9dir(&lst, &st, file, d, &str, str+nstr);
+ return d;
+}
+
diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
new file mode 100644
index 000000000..2646cba40
--- /dev/null
+++ b/src/lib9/dirwstat.c
@@ -0,0 +1,43 @@
+/*
+Plan 9 from User Space src/lib9/dirwstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirwstat.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include <sys/time.h>
+#include <utime.h>
+
+int
+dirwstat(char *file, Dir *dir)
+{
+ struct utimbuf ub;
+
+ /* BUG handle more */
+ if(~dir->mtime == 0)
+ return 0;
+
+ ub.actime = dir->mtime;
+ ub.modtime = dir->mtime;
+ return utime(file, &ub);
+}
diff --git a/src/lib9/dup.c b/src/lib9/dup.c
new file mode 100644
index 000000000..9fdfdb8d1
--- /dev/null
+++ b/src/lib9/dup.c
@@ -0,0 +1,36 @@
+/*
+Plan 9 from User Space src/lib9/dup.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dup.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+#undef dup
+
+int
+p9dup(int old, int new)
+{
+ if(new == -1)
+ return dup(old);
+ return dup2(old, new);
+}
diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
new file mode 100644
index 000000000..f42f2b538
--- /dev/null
+++ b/src/lib9/errstr.c
@@ -0,0 +1,106 @@
+/*
+Plan 9 from User Space src/lib9/errstr.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/errstr.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+ * We assume there's only one error buffer for the whole system.
+ * If you use ffork, you need to provide a _syserrstr. Since most
+ * people will use libthread (which provides a _syserrstr), this is
+ * okay.
+ */
+
+#include <u.h>
+#include <errno.h>
+#include <string.h>
+#include <libc.h>
+
+enum
+{
+ EPLAN9 = 0x19283745
+};
+
+char *(*_syserrstr)(void);
+static char xsyserr[ERRMAX];
+static char*
+getsyserr(void)
+{
+ char *s;
+
+ s = nil;
+ if(_syserrstr)
+ s = (*_syserrstr)();
+ if(s == nil)
+ s = xsyserr;
+ return s;
+}
+
+int
+errstr(char *err, uint n)
+{
+ char tmp[ERRMAX];
+ char *syserr;
+
+ strecpy(tmp, tmp+ERRMAX, err);
+ rerrstr(err, n);
+ syserr = getsyserr();
+ strecpy(syserr, syserr+ERRMAX, tmp);
+ errno = EPLAN9;
+ return 0;
+}
+
+void
+rerrstr(char *err, uint n)
+{
+ char *syserr;
+
+ syserr = getsyserr();
+ if(errno == EINTR)
+ strcpy(syserr, "interrupted");
+ else if(errno != EPLAN9)
+ strcpy(syserr, strerror(errno));
+ strecpy(err, err+n, syserr);
+}
+
+/* replaces __errfmt in libfmt */
+
+int
+__errfmt(Fmt *f)
+{
+ if(errno == EPLAN9)
+ return fmtstrcpy(f, getsyserr());
+ return fmtstrcpy(f, strerror(errno));
+}
+
+void
+werrstr(char *fmt, ...)
+{
+ va_list arg;
+ char buf[ERRMAX];
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+ERRMAX, fmt, arg);
+ va_end(arg);
+ errstr(buf, ERRMAX);
+}
+
diff --git a/src/lib9/exec.c b/src/lib9/exec.c
new file mode 100644
index 000000000..f2ad0f9b3
--- /dev/null
+++ b/src/lib9/exec.c
@@ -0,0 +1,33 @@
+/*
+Plan 9 from User Space src/lib9/exec.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/exec.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+int
+exec(char *prog, char *argv[])
+{
+ /* to mimic plan 9 should be just exec, but execvp is a better fit for unix */
+ return execvp(prog, argv);
+}
diff --git a/src/lib9/execl.c b/src/lib9/execl.c
new file mode 100644
index 000000000..9e42ad34b
--- /dev/null
+++ b/src/lib9/execl.c
@@ -0,0 +1,53 @@
+/*
+Plan 9 from User Space src/lib9/execl.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/execl.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+int
+execl(char *prog, ...)
+{
+ int i;
+ va_list arg;
+ char **argv;
+
+ va_start(arg, prog);
+ for(i=0; va_arg(arg, char*) != nil; i++)
+ ;
+ va_end(arg);
+
+ argv = malloc((i+1)*sizeof(char*));
+ if(argv == nil)
+ return -1;
+
+ va_start(arg, prog);
+ for(i=0; (argv[i] = va_arg(arg, char*)) != nil; i++)
+ ;
+ va_end(arg);
+
+ exec(prog, argv);
+ free(argv);
+ return -1;
+}
+
diff --git a/src/lib9/exitcode.c b/src/lib9/exitcode.c
new file mode 100644
index 000000000..234492acf
--- /dev/null
+++ b/src/lib9/exitcode.c
@@ -0,0 +1,34 @@
+/*
+Plan 9 from User Space src/lib9/exitcode.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/exitcode.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+int
+exitcode(char *s)
+{
+ return 1;
+}
+
diff --git a/src/lib9/fmt/charstod.c b/src/lib9/fmt/charstod.c
new file mode 100644
index 000000000..b8096e8fb
--- /dev/null
+++ b/src/lib9/fmt/charstod.c
@@ -0,0 +1,88 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp). The last call it makes to f terminates the
+ * scan, so is not a character in the number. It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+double
+fmtcharstod(int(*f)(void*), void *vp)
+{
+ double num, dem;
+ int neg, eneg, dig, exp, c;
+
+ num = 0;
+ neg = 0;
+ dig = 0;
+ exp = 0;
+ eneg = 0;
+
+ c = (*f)(vp);
+ while(c == ' ' || c == '\t')
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ if(c == '-')
+ neg = 1;
+ c = (*f)(vp);
+ }
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ c = (*f)(vp);
+ }
+ if(c == '.')
+ c = (*f)(vp);
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ dig++;
+ c = (*f)(vp);
+ }
+ if(c == 'e' || c == 'E'){
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ if(c == '-'){
+ dig = -dig;
+ eneg = 1;
+ }
+ c = (*f)(vp);
+ }
+ while(c >= '0' && c <= '9'){
+ exp = exp*10 + c-'0';
+ c = (*f)(vp);
+ }
+ }
+ exp -= dig;
+ if(exp < 0){
+ exp = -exp;
+ eneg = !eneg;
+ }
+ dem = __fmtpow10(exp);
+ if(eneg)
+ num /= dem;
+ else
+ num *= dem;
+ if(neg)
+ return -num;
+ return num;
+}
diff --git a/src/lib9/fmt/dofmt.c b/src/lib9/fmt/dofmt.c
new file mode 100644
index 000000000..ea43940d8
--- /dev/null
+++ b/src/lib9/fmt/dofmt.c
@@ -0,0 +1,629 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted */
+int
+dofmt(Fmt *f, char *fmt)
+{
+ Rune rune, *rt, *rs;
+ int r;
+ char *t, *s;
+ int n, nfmt;
+
+ nfmt = f->nfmt;
+ for(;;){
+ if(f->runes){
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ while((r = *(uchar*)fmt) && r != '%'){
+ if(r < Runeself)
+ fmt++;
+ else{
+ fmt += chartorune(&rune, fmt);
+ r = rune;
+ }
+ FMTRCHAR(f, rt, rs, r);
+ }
+ fmt++;
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = rs;
+ }else{
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ while((r = *(uchar*)fmt) && r != '%'){
+ if(r < Runeself){
+ FMTCHAR(f, t, s, r);
+ fmt++;
+ }else{
+ n = chartorune(&rune, fmt);
+ if(t + n > s){
+ t = (char*)__fmtflush(f, t, n);
+ if(t != nil)
+ s = (char*)f->stop;
+ else
+ return -1;
+ }
+ while(n--)
+ *t++ = *fmt++;
+ }
+ }
+ fmt++;
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = s;
+ }
+
+ fmt = (char*)__fmtdispatch(f, fmt, 0);
+ if(fmt == nil)
+ return -1;
+ }
+}
+
+void *
+__fmtflush(Fmt *f, void *t, int len)
+{
+ if(f->runes)
+ f->nfmt += (Rune*)t - (Rune*)f->to;
+ else
+ f->nfmt += (char*)t - (char *)f->to;
+ f->to = t;
+ if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+ f->stop = f->to;
+ return nil;
+ }
+ return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width characters (if FmtWidth is set)
+ */
+int
+__fmtpad(Fmt *f, int n)
+{
+ char *t, *s;
+ int i;
+
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ for(i = 0; i < n; i++)
+ FMTCHAR(f, t, s, ' ');
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ return 0;
+}
+
+int
+__rfmtpad(Fmt *f, int n)
+{
+ Rune *t, *s;
+ int i;
+
+ t = (Rune*)f->to;
+ s = (Rune*)f->stop;
+ for(i = 0; i < n; i++)
+ FMTRCHAR(f, t, s, ' ');
+ f->nfmt += t - (Rune *)f->to;
+ f->to = t;
+ return 0;
+}
+
+int
+__fmtcpy(Fmt *f, const void *vm, int n, int sz)
+{
+ Rune *rt, *rs, r;
+ char *t, *s, *m, *me;
+ ulong fl;
+ int nc, w;
+
+ m = (char*)vm;
+ me = m + sz;
+ fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ if((fl & FmtPrec) && n > f->prec)
+ n = f->prec;
+ if(f->runes){
+ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+ return -1;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+ return -1;
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRUNE(f, t, s, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+__fmtrcpy(Fmt *f, const void *vm, int n)
+{
+ Rune r, *m, *me, *rt, *rs;
+ char *t, *s;
+ ulong fl;
+ int w;
+
+ m = (Rune*)vm;
+ fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ if((fl & FmtPrec) && n > f->prec)
+ n = f->prec;
+ if(f->runes){
+ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+ return -1;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ for(me = m + n; m < me; m++)
+ FMTRCHAR(f, rt, rs, *m);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+ return -1;
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ for(me = m + n; m < me; m++){
+ r = *m;
+ FMTRUNE(f, t, s, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* fmt out one character */
+int
+__charfmt(Fmt *f)
+{
+ char x[1];
+
+ x[0] = va_arg(f->args, int);
+ f->prec = 1;
+ return __fmtcpy(f, (const char*)x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+__runefmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = va_arg(f->args, int);
+ return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+ int i, j;
+
+ if(!s)
+ return __fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+#ifdef PLAN9PORT
+ Rune r;
+ i = 0;
+ for(j=0; j<f->prec && s[i]; j++)
+ i += chartorune(&r, s+i);
+#else
+ /* ANSI requires precision in bytes, not Runes */
+ for(i=0; i<f->prec; i++)
+ if(s[i] == 0)
+ break;
+ j = utfnlen(s, i); /* won't print partial at end */
+#endif
+ return __fmtcpy(f, s, j, i);
+ }
+ return __fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+__strfmt(Fmt *f)
+{
+ char *s;
+
+ s = va_arg(f->args, char *);
+ return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+ Rune *e;
+ int n, p;
+
+ if(!s)
+ return __fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(n = 0; n < p; n++)
+ if(s[n] == 0)
+ break;
+ }else{
+ for(e = s; *e; e++)
+ ;
+ n = e - s;
+ }
+ return __fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+__runesfmt(Fmt *f)
+{
+ Rune *s;
+
+ s = va_arg(f->args, Rune *);
+ return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+__percentfmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = f->r;
+ f->prec = 1;
+ return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* fmt an integer */
+int
+__ifmt(Fmt *f)
+{
+ char buf[140], *p, *conv;
+ /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
+ uvlong vu;
+ ulong u;
+ int neg, base, i, n, fl, w, isv;
+ int ndig, len, excess, bytelen;
+ char *grouping;
+ char *thousands;
+
+ neg = 0;
+ fl = f->flags;
+ isv = 0;
+ vu = 0;
+ u = 0;
+#ifndef PLAN9PORT
+ /*
+ * Unsigned verbs for ANSI C
+ */
+ switch(f->r){
+ case 'o':
+ case 'p':
+ case 'u':
+ case 'x':
+ case 'X':
+ fl |= FmtUnsigned;
+ fl &= ~(FmtSign|FmtSpace);
+ break;
+ }
+#endif
+ if(f->r == 'p'){
+ u = (ulong)va_arg(f->args, void*);
+ f->r = 'x';
+ fl |= FmtUnsigned;
+ }else if(fl & FmtVLong){
+ isv = 1;
+ if(fl & FmtUnsigned)
+ vu = va_arg(f->args, uvlong);
+ else
+ vu = va_arg(f->args, vlong);
+ }else if(fl & FmtLong){
+ if(fl & FmtUnsigned)
+ u = va_arg(f->args, ulong);
+ else
+ u = va_arg(f->args, long);
+ }else if(fl & FmtByte){
+ if(fl & FmtUnsigned)
+ u = (uchar)va_arg(f->args, int);
+ else
+ u = (char)va_arg(f->args, int);
+ }else if(fl & FmtShort){
+ if(fl & FmtUnsigned)
+ u = (ushort)va_arg(f->args, int);
+ else
+ u = (short)va_arg(f->args, int);
+ }else{
+ if(fl & FmtUnsigned)
+ u = va_arg(f->args, uint);
+ else
+ u = va_arg(f->args, int);
+ }
+ conv = "0123456789abcdef";
+ grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */
+ thousands = f->thousands;
+ switch(f->r){
+ case 'd':
+ case 'i':
+ case 'u':
+ base = 10;
+ grouping = f->grouping;
+ break;
+ case 'X':
+ conv = "0123456789ABCDEF";
+ /* fall through */
+ case 'x':
+ base = 16;
+ thousands = ":";
+ break;
+ case 'b':
+ base = 2;
+ thousands = ":";
+ break;
+ case 'o':
+ base = 8;
+ break;
+ default:
+ return -1;
+ }
+ if(!(fl & FmtUnsigned)){
+ if(isv && (vlong)vu < 0){
+ vu = -(vlong)vu;
+ neg = 1;
+ }else if(!isv && (long)u < 0){
+ u = -(long)u;
+ neg = 1;
+ }
+ }
+ p = buf + sizeof buf - 1;
+ n = 0; /* in runes */
+ excess = 0; /* number of bytes > number runes */
+ ndig = 0;
+ len = utflen(thousands);
+ bytelen = strlen(thousands);
+ if(isv){
+ while(vu){
+ i = vu % base;
+ vu /= base;
+ if((fl & FmtComma) && n % 4 == 3){
+ *p-- = ',';
+ n++;
+ }
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = conv[i];
+ n++;
+ }
+ }else{
+ while(u){
+ i = u % base;
+ u /= base;
+ if((fl & FmtComma) && n % 4 == 3){
+ *p-- = ',';
+ n++;
+ }
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = conv[i];
+ n++;
+ }
+ }
+ if(n == 0){
+ /*
+ * "The result of converting a zero value with
+ * a precision of zero is no characters." - ANSI
+ *
+ * "For o conversion, # increases the precision, if and only if
+ * necessary, to force the first digit of the result to be a zero
+ * (if the value and precision are both 0, a single 0 is printed)." - ANSI
+ */
+ if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
+ *p-- = '0';
+ n = 1;
+ if(fl & FmtApost)
+ __needsep(&ndig, &grouping);
+ }
+
+ /*
+ * Zero values don't get 0x.
+ */
+ if(f->r == 'x' || f->r == 'X')
+ fl &= ~FmtSharp;
+ }
+ for(w = f->prec; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = '0';
+ }
+ if(neg || (fl & (FmtSign|FmtSpace)))
+ n++;
+ if(fl & FmtSharp){
+ if(base == 16)
+ n += 2;
+ else if(base == 8){
+ if(p[1] == '0')
+ fl &= ~FmtSharp;
+ else
+ n++;
+ }
+ }
+ if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ for(; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
+ *p-- = '0';
+ }
+ f->flags &= ~FmtWidth;
+ }
+ if(fl & FmtSharp){
+ if(base == 16)
+ *p-- = f->r;
+ if(base == 16 || base == 8)
+ *p-- = '0';
+ }
+ if(neg)
+ *p-- = '-';
+ else if(fl & FmtSign)
+ *p-- = '+';
+ else if(fl & FmtSpace)
+ *p-- = ' ';
+ f->flags &= ~FmtPrec;
+ return __fmtcpy(f, p + 1, n, n + excess);
+}
+
+int
+__countfmt(Fmt *f)
+{
+ void *p;
+ ulong fl;
+
+ fl = f->flags;
+ p = va_arg(f->args, void*);
+ if(fl & FmtVLong){
+ *(vlong*)p = f->nfmt;
+ }else if(fl & FmtLong){
+ *(long*)p = f->nfmt;
+ }else if(fl & FmtByte){
+ *(char*)p = f->nfmt;
+ }else if(fl & FmtShort){
+ *(short*)p = f->nfmt;
+ }else{
+ *(int*)p = f->nfmt;
+ }
+ return 0;
+}
+
+int
+__flagfmt(Fmt *f)
+{
+ switch(f->r){
+ case ',':
+ f->flags |= FmtComma;
+ break;
+ case '-':
+ f->flags |= FmtLeft;
+ break;
+ case '+':
+ f->flags |= FmtSign;
+ break;
+ case '#':
+ f->flags |= FmtSharp;
+ break;
+ case '\'':
+ f->flags |= FmtApost;
+ break;
+ case ' ':
+ f->flags |= FmtSpace;
+ break;
+ case 'u':
+ f->flags |= FmtUnsigned;
+ break;
+ case 'h':
+ if(f->flags & FmtShort)
+ f->flags |= FmtByte;
+ f->flags |= FmtShort;
+ break;
+ case 'L':
+ f->flags |= FmtLDouble;
+ break;
+ case 'l':
+ if(f->flags & FmtLong)
+ f->flags |= FmtVLong;
+ f->flags |= FmtLong;
+ break;
+ }
+ return 1;
+}
+
+/* default error format */
+int
+__badfmt(Fmt *f)
+{
+ char x[3];
+
+ x[0] = '%';
+ x[1] = f->r;
+ x[2] = '%';
+ f->prec = 3;
+ __fmtcpy(f, (const void*)x, 3, 3);
+ return 0;
+}
diff --git a/src/lib9/fmt/dorfmt.c b/src/lib9/fmt/dorfmt.c
new file mode 100644
index 000000000..672742f02
--- /dev/null
+++ b/src/lib9/fmt/dorfmt.c
@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted */
+
+/* BUG: THIS FILE IS NOT UPDATED TO THE NEW SPEC */
+int
+dorfmt(Fmt *f, const Rune *fmt)
+{
+ Rune *rt, *rs;
+ int r;
+ char *t, *s;
+ int nfmt;
+
+ nfmt = f->nfmt;
+ for(;;){
+ if(f->runes){
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ while((r = *fmt++) && r != '%'){
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = rs;
+ }else{
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ while((r = *fmt++) && r != '%'){
+ FMTRUNE(f, t, f->stop, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = s;
+ }
+
+ fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
+ if(fmt == nil)
+ return -1;
+ }
+ return 0; /* not reached */
+}
diff --git a/src/lib9/fmt/errfmt.c b/src/lib9/fmt/errfmt.c
new file mode 100644
index 000000000..66c9600f0
--- /dev/null
+++ b/src/lib9/fmt/errfmt.c
@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+__errfmt(Fmt *f)
+{
+ char *s;
+
+ s = strerror(errno);
+ return fmtstrcpy(f, s);
+}
diff --git a/src/lib9/fmt/fltfmt.c b/src/lib9/fmt/fltfmt.c
new file mode 100644
index 000000000..3ce8babb0
--- /dev/null
+++ b/src/lib9/fmt/fltfmt.c
@@ -0,0 +1,677 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <errno.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+enum
+{
+ FDIGIT = 30,
+ FDEFLT = 6,
+ NSIGNIF = 17
+};
+
+/*
+ * first few powers of 10, enough for about 1/2 of the
+ * total space for doubles.
+ */
+static double pows10[] =
+{
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
+ 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
+ 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
+ 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
+ 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
+ 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
+ 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
+ 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
+ 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
+ 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
+ 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
+ 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
+ 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
+ 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
+};
+#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
+#undef pow10
+#define pow10 fmtpow10
+
+static double
+pow10(int n)
+{
+ double d;
+ int neg;
+
+ neg = 0;
+ if(n < 0){
+ neg = 1;
+ n = -n;
+ }
+
+ if(n < npows10)
+ d = pows10[n];
+ else{
+ d = pows10[npows10-1];
+ for(;;){
+ n -= npows10 - 1;
+ if(n < npows10){
+ d *= pows10[n];
+ break;
+ }
+ d *= pows10[npows10 - 1];
+ }
+ }
+ if(neg)
+ return 1./d;
+ return d;
+}
+
+/*
+ * add 1 to the decimal integer string a of length n.
+ * if 99999 overflows into 10000, return 1 to tell caller
+ * to move the virtual decimal point.
+ */
+static int
+xadd1(char *a, int n)
+{
+ char *b;
+ int c;
+
+ if(n < 0 || n > NSIGNIF)
+ return 0;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b + 1;
+ if(c <= '9') {
+ *b = c;
+ return 0;
+ }
+ *b = '0';
+ }
+ /*
+ * need to overflow adding digit.
+ * shift number down and insert 1 at beginning.
+ * decimal is known to be 0s or we wouldn't
+ * have gotten this far. (e.g., 99999+1 => 00000)
+ */
+ a[0] = '1';
+ return 1;
+}
+
+/*
+ * subtract 1 from the decimal integer string a.
+ * if 10000 underflows into 09999, make it 99999
+ * and return 1 to tell caller to move the virtual
+ * decimal point. this way, xsub1 is inverse of xadd1.
+ */
+static int
+xsub1(char *a, int n)
+{
+ char *b;
+ int c;
+
+ if(n < 0 || n > NSIGNIF)
+ return 0;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b - 1;
+ if(c >= '0') {
+ if(c == '0' && b == a) {
+ /*
+ * just zeroed the top digit; shift everyone up.
+ * decimal is known to be 9s or we wouldn't
+ * have gotten this far. (e.g., 10000-1 => 09999)
+ */
+ *b = '9';
+ return 1;
+ }
+ *b = c;
+ return 0;
+ }
+ *b = '9';
+ }
+ /*
+ * can't get here. the number a is always normalized
+ * so that it has a nonzero first digit.
+ */
+ abort();
+}
+
+/*
+ * format exponent like sprintf(p, "e%+02d", e)
+ */
+static void
+xfmtexp(char *p, int e, int ucase)
+{
+ char se[9];
+ int i;
+
+ *p++ = ucase ? 'E' : 'e';
+ if(e < 0) {
+ *p++ = '-';
+ e = -e;
+ } else
+ *p++ = '+';
+ i = 0;
+ while(e) {
+ se[i++] = e % 10 + '0';
+ e /= 10;
+ }
+ while(i < 2)
+ se[i++] = '0';
+ while(i > 0)
+ *p++ = se[--i];
+ *p++ = '\0';
+}
+
+/*
+ * compute decimal integer m, exp such that:
+ * f = m*10^exp
+ * m is as short as possible with losing exactness
+ * assumes special cases (NaN, +Inf, -Inf) have been handled.
+ */
+static void
+xdtoa(double f, char *s, int *exp, int *neg, int *ns)
+{
+ int c, d, e2, e, ee, i, ndigit, oerrno;
+ char tmp[NSIGNIF+10];
+ double g;
+
+ oerrno = errno; /* in case strtod smashes errno */
+
+ /*
+ * make f non-negative.
+ */
+ *neg = 0;
+ if(f < 0) {
+ f = -f;
+ *neg = 1;
+ }
+
+ /*
+ * must handle zero specially.
+ */
+ if(f == 0){
+ *exp = 0;
+ s[0] = '0';
+ s[1] = '\0';
+ *ns = 1;
+ return;
+ }
+
+ /*
+ * find g,e such that f = g*10^e.
+ * guess 10-exponent using 2-exponent, then fine tune.
+ */
+ frexp(f, &e2);
+ e = (int)(e2 * .301029995664);
+ g = f * pow10(-e);
+ while(g < 1) {
+ e--;
+ g = f * pow10(-e);
+ }
+ while(g >= 10) {
+ e++;
+ g = f * pow10(-e);
+ }
+
+ /*
+ * convert NSIGNIF digits as a first approximation.
+ */
+ for(i=0; i<NSIGNIF; i++) {
+ d = (int)g;
+ s[i] = d+'0';
+ g = (g-d) * 10;
+ }
+ s[i] = 0;
+
+ /*
+ * adjust e because s is 314159... not 3.14159...
+ */
+ e -= NSIGNIF-1;
+ xfmtexp(s+NSIGNIF, e, 0);
+
+ /*
+ * adjust conversion until strtod(s) == f exactly.
+ */
+ for(i=0; i<10; i++) {
+ g = strtod(s, nil);
+ if(f > g) {
+ if(xadd1(s, NSIGNIF)) {
+ /* gained a digit */
+ e--;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
+ continue;
+ }
+ if(f < g) {
+ if(xsub1(s, NSIGNIF)) {
+ /* lost a digit */
+ e++;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * play with the decimal to try to simplify.
+ */
+
+ /*
+ * bump last few digits up to 9 if we can
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '9') {
+ s[i] = '9';
+ g = strtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * add 1 in hopes of turning 9s to 0s
+ */
+ if(s[NSIGNIF-1] == '9') {
+ strcpy(tmp, s);
+ ee = e;
+ if(xadd1(tmp, NSIGNIF)) {
+ ee--;
+ xfmtexp(tmp+NSIGNIF, ee, 0);
+ }
+ g = strtod(tmp, nil);
+ if(g == f) {
+ strcpy(s, tmp);
+ e = ee;
+ }
+ }
+
+ /*
+ * bump last few digits down to 0 as we can.
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '0') {
+ s[i] = '0';
+ g = strtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * remove trailing zeros.
+ */
+ ndigit = NSIGNIF;
+ while(ndigit > 1 && s[ndigit-1] == '0'){
+ e++;
+ --ndigit;
+ }
+ s[ndigit] = 0;
+ *exp = e;
+ *ns = ndigit;
+ errno = oerrno;
+}
+
+#ifdef PLAN9PORT
+static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
+#else
+static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
+#endif
+
+int
+__efgfmt(Fmt *fmt)
+{
+ char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
+ double f;
+ int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
+ int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
+ Rune r, *rs, *rt;
+
+ if(fmt->flags&FmtLong)
+ f = va_arg(fmt->args, long double);
+ else
+ f = va_arg(fmt->args, double);
+
+ /*
+ * extract formatting flags
+ */
+ fl = fmt->flags;
+ fmt->flags = 0;
+ prec = FDEFLT;
+ if(fl & FmtPrec)
+ prec = fmt->prec;
+ chr = fmt->r;
+ ucase = 0;
+ switch(chr) {
+ case 'A':
+ case 'E':
+ case 'F':
+ case 'G':
+ chr += 'a'-'A';
+ ucase = 1;
+ break;
+ }
+
+ /*
+ * pick off special numbers.
+ */
+ if(__isNaN(f)) {
+ s = special[0+ucase];
+ special:
+ fmt->flags = fl & (FmtWidth|FmtLeft);
+ return __fmtcpy(fmt, s, strlen(s), strlen(s));
+ }
+ if(__isInf(f, 1)) {
+ s = special[2+ucase];
+ goto special;
+ }
+ if(__isInf(f, -1)) {
+ s = special[4+ucase];
+ goto special;
+ }
+
+ /*
+ * get exact representation.
+ */
+ digits = buf;
+ xdtoa(f, digits, &exp, &neg, &ndigits);
+
+ /*
+ * get locale's decimal point.
+ */
+ dot = fmt->decimal;
+ if(dot == nil)
+ dot = ".";
+ dotwid = utflen(dot);
+
+ /*
+ * now the formatting fun begins.
+ * compute parameters for actual fmt:
+ *
+ * pad: number of spaces to insert before/after field.
+ * z1: number of zeros to insert before digits
+ * z2: number of zeros to insert after digits
+ * point: number of digits to print before decimal point
+ * ndigits: number of digits to use from digits[]
+ * suf: trailing suffix, like "e-5"
+ */
+ realchr = chr;
+ switch(chr){
+ case 'g':
+ /*
+ * convert to at most prec significant digits. (prec=0 means 1)
+ */
+ if(prec == 0)
+ prec = 1;
+ if(ndigits > prec) {
+ if(digits[prec] >= '5' && xadd1(digits, prec))
+ exp++;
+ exp += ndigits-prec;
+ ndigits = prec;
+ }
+
+ /*
+ * extra rules for %g (implemented below):
+ * trailing zeros removed after decimal unless FmtSharp.
+ * decimal point only if digit follows.
+ */
+
+ /* fall through to %e */
+ default:
+ case 'e':
+ /*
+ * one significant digit before decimal, no leading zeros.
+ */
+ point = 1;
+ z1 = 0;
+
+ /*
+ * decimal point is after ndigits digits right now.
+ * slide to be after first.
+ */
+ e = exp + (ndigits-1);
+
+ /*
+ * if this is %g, check exponent and convert prec
+ */
+ if(realchr == 'g') {
+ if(-4 <= e && e < prec)
+ goto casef;
+ prec--; /* one digit before decimal; rest after */
+ }
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(1+prec >= ndigits)
+ z2 = 1+prec - ndigits;
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = 1+prec;
+ if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * had 999e4, now have 100e5
+ */
+ e++;
+ }
+ ndigits = newndigits;
+ z2 = 0;
+ }
+ xfmtexp(suf, e, ucase);
+ sufwid = strlen(suf);
+ break;
+
+ casef:
+ case 'f':
+ /*
+ * determine where digits go with respect to decimal point
+ */
+ if(ndigits+exp > 0) {
+ point = ndigits+exp;
+ z1 = 0;
+ } else {
+ point = 1;
+ z1 = 1 + -(ndigits+exp);
+ }
+
+ /*
+ * %g specifies prec = number of significant digits
+ * convert to number of digits after decimal point
+ */
+ if(realchr == 'g')
+ prec += z1 - point;
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(point+prec >= z1+ndigits)
+ z2 = point+prec - (z1+ndigits);
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = point+prec - z1;
+ if(newndigits < 0) {
+ z1 += newndigits;
+ newndigits = 0;
+ } else if(newndigits == 0) {
+ /* perhaps round up */
+ if(digits[0] >= '5'){
+ digits[0] = '1';
+ newndigits = 1;
+ goto newdigit;
+ }
+ } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * digits was 999, is now 100; make it 1000
+ */
+ digits[newndigits++] = '0';
+ newdigit:
+ /*
+ * account for new digit
+ */
+ if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/
+ z1--;
+ else /* 9.99 => 10.00 */
+ point++;
+ }
+ z2 = 0;
+ ndigits = newndigits;
+ }
+ sufwid = 0;
+ break;
+ }
+
+ /*
+ * if %g is given without FmtSharp, remove trailing zeros.
+ * must do after truncation, so that e.g. print %.3g 1.001
+ * produces 1, not 1.00. sorry, but them's the rules.
+ */
+ if(realchr == 'g' && !(fl & FmtSharp)) {
+ if(z1+ndigits+z2 >= point) {
+ if(z1+ndigits < point)
+ z2 = point - (z1+ndigits);
+ else{
+ z2 = 0;
+ while(z1+ndigits > point && digits[ndigits-1] == '0')
+ ndigits--;
+ }
+ }
+ }
+
+ /*
+ * compute width of all digits and decimal point and suffix if any
+ */
+ wid = z1+ndigits+z2;
+ if(wid > point)
+ wid += dotwid;
+ else if(wid == point){
+ if(fl & FmtSharp)
+ wid += dotwid;
+ else
+ point++; /* do not print any decimal point */
+ }
+ wid += sufwid;
+
+ /*
+ * determine sign
+ */
+ sign = 0;
+ if(neg)
+ sign = '-';
+ else if(fl & FmtSign)
+ sign = '+';
+ else if(fl & FmtSpace)
+ sign = ' ';
+ if(sign)
+ wid++;
+
+ /*
+ * compute padding
+ */
+ pad = 0;
+ if((fl & FmtWidth) && fmt->width > wid)
+ pad = fmt->width - wid;
+ if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
+ z1 += pad;
+ point += pad;
+ pad = 0;
+ }
+
+ /*
+ * format the actual field. too bad about doing this twice.
+ */
+ if(fmt->runes){
+ if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ rt = (Rune*)fmt->to;
+ rs = (Rune*)fmt->stop;
+ if(sign)
+ FMTRCHAR(fmt, rt, rs, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
+ }
+ FMTRCHAR(fmt, rt, rs, c);
+ if(--point == 0) {
+ for(p = dot; *p; ){
+ p += chartorune(&r, p);
+ FMTRCHAR(fmt, rt, rs, r);
+ }
+ }
+ }
+ fmt->nfmt += rt - (Rune*)fmt->to;
+ fmt->to = rt;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ }else{
+ if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
+ t = (char*)fmt->to;
+ s = (char*)fmt->stop;
+ if(sign)
+ FMTCHAR(fmt, t, s, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
+ }
+ FMTCHAR(fmt, t, s, c);
+ if(--point == 0)
+ for(p=dot; *p; p++)
+ FMTCHAR(fmt, t, s, *p);
+ }
+ fmt->nfmt += t - (char*)fmt->to;
+ fmt->to = t;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
new file mode 100644
index 000000000..7a747b1b1
--- /dev/null
+++ b/src/lib9/fmt/fmt.c
@@ -0,0 +1,235 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+enum
+{
+ Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+ int c;
+ volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+static struct
+{
+ /* lock by calling __fmtlock, __fmtunlock */
+ int nfmt;
+ Convfmt fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+ ' ', __flagfmt,
+ '#', __flagfmt,
+ '%', __percentfmt,
+ '\'', __flagfmt,
+ '+', __flagfmt,
+ ',', __flagfmt,
+ '-', __flagfmt,
+ 'C', __runefmt, /* Plan 9 addition */
+ 'E', __efgfmt,
+#ifndef PLAN9PORT
+ 'F', __efgfmt, /* ANSI only */
+#endif
+ 'G', __efgfmt,
+#ifndef PLAN9PORT
+ 'L', __flagfmt, /* ANSI only */
+#endif
+ 'S', __runesfmt, /* Plan 9 addition */
+ 'X', __ifmt,
+ 'b', __ifmt, /* Plan 9 addition */
+ 'c', __charfmt,
+ 'd', __ifmt,
+ 'e', __efgfmt,
+ 'f', __efgfmt,
+ 'g', __efgfmt,
+ 'h', __flagfmt,
+#ifndef PLAN9PORT
+ 'i', __ifmt, /* ANSI only */
+#endif
+ 'l', __flagfmt,
+ 'n', __countfmt,
+ 'o', __ifmt,
+ 'p', __ifmt,
+ 'r', __errfmt,
+ 's', __strfmt,
+#ifdef PLAN9PORT
+ 'u', __flagfmt,
+#else
+ 'u', __ifmt,
+#endif
+ 'x', __ifmt,
+ 0, nil,
+};
+
+
+int (*fmtdoquote)(int);
+
+/*
+ * __fmtlock() must be set
+ */
+static int
+__fmtinstall(int c, Fmts f)
+{
+ Convfmt *p, *ep;
+
+ if(c<=0 || c>=65536)
+ return -1;
+ if(!f)
+ f = __badfmt;
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ break;
+
+ if(p == &fmtalloc.fmt[Maxfmt])
+ return -1;
+
+ p->fmt = f;
+ if(p == ep){ /* installing a new format character */
+ fmtalloc.nfmt++;
+ p->c = c;
+ }
+
+ return 0;
+}
+
+int
+fmtinstall(int c, int (*f)(Fmt*))
+{
+ int ret;
+
+ __fmtlock();
+ ret = __fmtinstall(c, f);
+ __fmtunlock();
+ return ret;
+}
+
+static Fmts
+fmtfmt(int c)
+{
+ Convfmt *p, *ep;
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c){
+ while(p->fmt == nil) /* loop until value is updated */
+ ;
+ return p->fmt;
+ }
+
+ /* is this a predefined format char? */
+ __fmtlock();
+ for(p=knownfmt; p->c; p++)
+ if(p->c == c){
+ __fmtinstall(p->c, p->fmt);
+ __fmtunlock();
+ return p->fmt;
+ }
+ __fmtunlock();
+
+ return __badfmt;
+}
+
+void*
+__fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+ Rune rune, r;
+ int i, n;
+
+ f->flags = 0;
+ f->width = f->prec = 0;
+
+ for(;;){
+ if(isrunes){
+ r = *(Rune*)fmt;
+ fmt = (Rune*)fmt + 1;
+ }else{
+ fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
+ r = rune;
+ }
+ f->r = r;
+ switch(r){
+ case '\0':
+ return nil;
+ case '.':
+ f->flags |= FmtWidth|FmtPrec;
+ continue;
+ case '0':
+ if(!(f->flags & FmtWidth)){
+ f->flags |= FmtZero;
+ continue;
+ }
+ /* fall through */
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ i = 0;
+ while(r >= '0' && r <= '9'){
+ i = i * 10 + r - '0';
+ if(isrunes){
+ r = *(Rune*)fmt;
+ fmt = (Rune*)fmt + 1;
+ }else{
+ r = *(char*)fmt;
+ fmt = (char*)fmt + 1;
+ }
+ }
+ if(isrunes)
+ fmt = (Rune*)fmt - 1;
+ else
+ fmt = (char*)fmt - 1;
+ numflag:
+ if(f->flags & FmtWidth){
+ f->flags |= FmtPrec;
+ f->prec = i;
+ }else{
+ f->flags |= FmtWidth;
+ f->width = i;
+ }
+ continue;
+ case '*':
+ i = va_arg(f->args, int);
+ if(i < 0){
+ /*
+ * negative precision =>
+ * ignore the precision.
+ */
+ if(f->flags & FmtPrec){
+ f->flags &= ~FmtPrec;
+ f->prec = 0;
+ continue;
+ }
+ i = -i;
+ f->flags |= FmtLeft;
+ }
+ goto numflag;
+ }
+ n = (*fmtfmt(r))(f);
+ if(n < 0)
+ return nil;
+ if(n == 0)
+ return fmt;
+ }
+}
diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
new file mode 100644
index 000000000..74cb8a8d2
--- /dev/null
+++ b/src/lib9/fmt/fmtdef.h
@@ -0,0 +1,119 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+ int quoted; /* if set, string must be quoted */
+ int nrunesin; /* number of input runes that can be accepted */
+ int nbytesin; /* number of input bytes that can be accepted */
+ int nrunesout; /* number of runes that will be generated */
+ int nbytesout; /* number of bytes that will be generated */
+};
+
+/* Edit .+1,/^$/ |cfn |grep -v static | grep __ */
+double __Inf(int sign);
+double __NaN(void);
+int __badfmt(Fmt *f);
+int __charfmt(Fmt *f);
+int __countfmt(Fmt *f);
+int __efgfmt(Fmt *fmt);
+int __errfmt(Fmt *f);
+int __flagfmt(Fmt *f);
+int __fmtFdFlush(Fmt *f);
+int __fmtcpy(Fmt *f, const void *vm, int n, int sz);
+void* __fmtdispatch(Fmt *f, void *fmt, int isrunes);
+void * __fmtflush(Fmt *f, void *t, int len);
+void __fmtlock(void);
+int __fmtpad(Fmt *f, int n);
+double __fmtpow10(int n);
+int __fmtrcpy(Fmt *f, const void *vm, int n);
+void __fmtunlock(void);
+int __ifmt(Fmt *f);
+int __isInf(double d, int sign);
+int __isNaN(double d);
+int __needsep(int*, char**);
+int __needsquotes(char *s, int *quotelenp);
+int __percentfmt(Fmt *f);
+void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
+int __quotestrfmt(int runesin, Fmt *f);
+int __rfmtpad(Fmt *f, int n);
+int __runefmt(Fmt *f);
+int __runeneedsquotes(Rune *r, int *quotelenp);
+int __runesfmt(Fmt *f);
+int __strfmt(Fmt *f);
+
+#define FMTCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (char*)s){\
+ t = (char*)__fmtflush(f, t, 1);\
+ if(t != nil)\
+ s = (char*)f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (Rune*)s){\
+ t = (Rune*)__fmtflush(f, t, sizeof(Rune));\
+ if(t != nil)\
+ s = (Rune*)f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRUNE(f, t, s, r)\
+ do{\
+ Rune _rune;\
+ int _runelen;\
+ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+ t = (char*)__fmtflush(f, t, _runelen);\
+ if(t != nil)\
+ s = (char*)f->stop;\
+ else\
+ return -1;\
+ }\
+ if(r < Runeself)\
+ *t++ = r;\
+ else{\
+ _rune = r;\
+ t += runetochar(t, &_rune);\
+ }\
+ }while(0)
+
+#ifdef va_copy
+# define VA_COPY(a,b) va_copy(a,b)
+# define VA_END(a) va_end(a)
+#else
+# define VA_COPY(a,b) (a) = (b)
+# define VA_END(a)
+#endif
+
diff --git a/src/lib9/fmt/fmtfd.c b/src/lib9/fmt/fmtfd.c
new file mode 100644
index 000000000..c32abf115
--- /dev/null
+++ b/src/lib9/fmt/fmtfd.c
@@ -0,0 +1,51 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * public routine for final flush of a formatting buffer
+ * to a file descriptor; returns total char count.
+ */
+int
+fmtfdflush(Fmt *f)
+{
+ if(__fmtFdFlush(f) <= 0)
+ return -1;
+ return f->nfmt;
+}
+
+/*
+ * initialize an output buffer for buffered printing
+ */
+int
+fmtfdinit(Fmt *f, int fd, char *buf, int size)
+{
+ f->runes = 0;
+ f->start = buf;
+ f->to = buf;
+ f->stop = buf + size;
+ f->flush = __fmtFdFlush;
+ f->farg = (void*)(uintptr_t)fd;
+ f->flags = 0;
+ f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
diff --git a/src/lib9/fmt/fmtfdflush.c b/src/lib9/fmt/fmtfdflush.c
new file mode 100644
index 000000000..c9854cee5
--- /dev/null
+++ b/src/lib9/fmt/fmtfdflush.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * generic routine for flushing a formatting buffer
+ * to a file descriptor
+ */
+int
+__fmtFdFlush(Fmt *f)
+{
+ int n;
+
+ n = (char*)f->to - (char*)f->start;
+ if(n && write((uintptr)f->farg, f->start, n) != n)
+ return 0;
+ f->to = f->start;
+ return 1;
+}
diff --git a/src/lib9/fmt/fmtlocale.c b/src/lib9/fmt/fmtlocale.c
new file mode 100644
index 000000000..64ed10f7b
--- /dev/null
+++ b/src/lib9/fmt/fmtlocale.c
@@ -0,0 +1,69 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * Fill in the internationalization stuff in the State structure.
+ * For nil arguments, provide the sensible defaults:
+ * decimal is a period
+ * thousands separator is a comma
+ * thousands are marked every three digits
+ */
+void
+fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
+{
+ if(decimal == nil || decimal[0] == '\0')
+ decimal = ".";
+ if(thousands == nil)
+ thousands = ",";
+ if(grouping == nil)
+ grouping = "\3";
+ f->decimal = decimal;
+ f->thousands = thousands;
+ f->grouping = grouping;
+}
+
+/*
+ * We are about to emit a digit in e.g. %'d. If that digit would
+ * overflow a thousands (e.g.) grouping, tell the caller to emit
+ * the thousands separator. Always advance the digit counter
+ * and pointer into the grouping descriptor.
+ */
+int
+__needsep(int *ndig, char **grouping)
+{
+ int group;
+
+ (*ndig)++;
+ group = *(unsigned char*)*grouping;
+ /* CHAR_MAX means no further grouping. \0 means we got the empty string */
+ if(group == 0xFF || group == 0x7f || group == 0x00)
+ return 0;
+ if(*ndig > group){
+ /* if we're at end of string, continue with this grouping; else advance */
+ if((*grouping)[1] != '\0')
+ (*grouping)++;
+ *ndig = 1;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
new file mode 100644
index 000000000..297acd8f9
--- /dev/null
+++ b/src/lib9/fmt/fmtlock.c
@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+void
+__fmtlock(void)
+{
+}
+
+void
+__fmtunlock(void)
+{
+}
diff --git a/src/lib9/fmt/fmtnull.c b/src/lib9/fmt/fmtnull.c
new file mode 100644
index 000000000..b8caacbf7
--- /dev/null
+++ b/src/lib9/fmt/fmtnull.c
@@ -0,0 +1,48 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * Absorb output without using resources.
+ */
+static Rune nullbuf[32];
+
+static int
+__fmtnullflush(Fmt *f)
+{
+ f->to = nullbuf;
+ f->nfmt = 0;
+ return 0;
+}
+
+int
+fmtnullinit(Fmt *f)
+{
+ memset(f, 0, sizeof *f);
+ f->runes = 1;
+ f->start = nullbuf;
+ f->to = nullbuf;
+ f->stop = nullbuf+nelem(nullbuf);
+ f->flush = __fmtnullflush;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
+
diff --git a/src/lib9/fmt/fmtprint.c b/src/lib9/fmt/fmtprint.c
new file mode 100644
index 000000000..8a29e6faf
--- /dev/null
+++ b/src/lib9/fmt/fmtprint.c
@@ -0,0 +1,51 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+ va_list va;
+ int n;
+
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_COPY(va, f->args);
+ VA_END(f->args);
+ va_start(f->args, fmt);
+ n = dofmt(f, fmt);
+ va_end(f->args);
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_COPY(f->args,va);
+ VA_END(va);
+ if(n >= 0)
+ return 0;
+ return n;
+}
+
diff --git a/src/lib9/fmt/fmtquote.c b/src/lib9/fmt/fmtquote.c
new file mode 100644
index 000000000..b9ac772ed
--- /dev/null
+++ b/src/lib9/fmt/fmtquote.c
@@ -0,0 +1,274 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by __quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ * NUL in input
+ * count exceeded in input
+ * count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+ int w;
+ Rune c;
+
+ q->quoted = 0;
+ q->nbytesout = 0;
+ q->nrunesout = 0;
+ q->nbytesin = 0;
+ q->nrunesin = 0;
+ if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+ if(nout < 2)
+ return;
+ q->quoted = 1;
+ q->nbytesout = 2;
+ q->nrunesout = 2;
+ }
+ for(; nin!=0; nin--){
+ if(s)
+ w = chartorune(&c, s);
+ else{
+ c = *r;
+ w = runelen(c);
+ }
+
+ if(c == '\0')
+ break;
+ if(runesout){
+ if(q->nrunesout+1 > nout)
+ break;
+ }else{
+ if(q->nbytesout+w > nout)
+ break;
+ }
+
+ if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
+ if(!q->quoted){
+ if(runesout){
+ if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
+ break;
+ }else{
+ if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
+ break;
+ }
+ q->nrunesout += 2; /* include quotes */
+ q->nbytesout += 2; /* include quotes */
+ q->quoted = 1;
+ }
+ if(c == '\'') {
+ if(runesout){
+ if(1+q->nrunesout+1 > nout) /* no room for quotes */
+ break;
+ }else{
+ if(1+q->nbytesout+w > nout) /* no room for quotes */
+ break;
+ }
+ q->nbytesout++;
+ q->nrunesout++; /* quotes reproduce as two characters */
+ }
+ }
+
+ /* advance input */
+ if(s)
+ s += w;
+ else
+ r++;
+ q->nbytesin += w;
+ q->nrunesin++;
+
+ /* advance output */
+ q->nbytesout += w;
+ q->nrunesout++;
+
+#ifndef PLAN9PORT
+ /* ANSI requires precision in bytes, not Runes. */
+ nin-= w-1; /* and then n-- in the loop */
+#endif
+ }
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+ Rune r, *rm, *rme;
+ char *t, *s, *m, *me;
+ Rune *rt, *rs;
+ ulong fl;
+ int nc, w;
+
+ m = sin;
+ me = m + q->nbytesin;
+ rm = rin;
+ rme = rm + q->nrunesin;
+
+ fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ if(f->runes){
+ if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ t = (char*)f->to;
+ s = (char*)f->stop;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
+ if(f->runes)
+ FMTRCHAR(f, rt, rs, '\'');
+ else
+ FMTRUNE(f, t, s, '\'');
+ for(nc = q->nrunesin; nc > 0; nc--){
+ if(sin){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ }else{
+ if(rm >= rme)
+ break;
+ r = *(uchar*)rm++;
+ }
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, r);
+ if(r == '\'')
+ FMTRCHAR(f, rt, rs, r);
+ }else{
+ FMTRUNE(f, t, s, r);
+ if(r == '\'')
+ FMTRUNE(f, t, s, r);
+ }
+ }
+
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, '\'');
+ USED(rs);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ FMTRUNE(f, t, s, '\'');
+ USED(s);
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+__quotestrfmt(int runesin, Fmt *f)
+{
+ int nin, outlen;
+ Rune *r;
+ char *s;
+ Quoteinfo q;
+
+ nin = -1;
+ if(f->flags&FmtPrec)
+ nin = f->prec;
+ if(runesin){
+ r = va_arg(f->args, Rune *);
+ s = nil;
+ }else{
+ s = va_arg(f->args, char *);
+ r = nil;
+ }
+ if(!s && !r)
+ return __fmtcpy(f, (void*)"<nil>", 5, 5);
+
+ if(f->flush)
+ outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
+ else if(f->runes)
+ outlen = (Rune*)f->stop - (Rune*)f->to;
+ else
+ outlen = (char*)f->stop - (char*)f->to;
+
+ __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
+/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
+
+ if(runesin){
+ if(!q.quoted)
+ return __fmtrcpy(f, r, q.nrunesin);
+ return qstrfmt(nil, r, &q, f);
+ }
+
+ if(!q.quoted)
+ return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
+ return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+ return __quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+ return __quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+ fmtinstall('q', quotestrfmt);
+ fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+__needsquotes(char *s, int *quotelenp)
+{
+ Quoteinfo q;
+
+ __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nbytesout;
+
+ return q.quoted;
+}
+
+int
+__runeneedsquotes(Rune *r, int *quotelenp)
+{
+ Quoteinfo q;
+
+ __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nrunesout;
+
+ return q.quoted;
+}
diff --git a/src/lib9/fmt/fmtrune.c b/src/lib9/fmt/fmtrune.c
new file mode 100644
index 000000000..da8c5d746
--- /dev/null
+++ b/src/lib9/fmt/fmtrune.c
@@ -0,0 +1,43 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+fmtrune(Fmt *f, int r)
+{
+ Rune *rt;
+ char *t;
+ int n;
+
+ if(f->runes){
+ rt = (Rune*)f->to;
+ FMTRCHAR(f, rt, f->stop, r);
+ f->to = rt;
+ n = 1;
+ }else{
+ t = (char*)f->to;
+ FMTRUNE(f, t, f->stop, r);
+ n = t - (char*)f->to;
+ f->to = t;
+ }
+ f->nfmt += n;
+ return 0;
+}
diff --git a/src/lib9/fmt/fmtstr.c b/src/lib9/fmt/fmtstr.c
new file mode 100644
index 000000000..a6ca7721d
--- /dev/null
+++ b/src/lib9/fmt/fmtstr.c
@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+fmtstrflush(Fmt *f)
+{
+ if(f->start == nil)
+ return nil;
+ *(char*)f->to = '\0';
+ f->to = f->start;
+ return (char*)f->start;
+}
diff --git a/src/lib9/fmt/fmtvprint.c b/src/lib9/fmt/fmtvprint.c
new file mode 100644
index 000000000..6acd37a51
--- /dev/null
+++ b/src/lib9/fmt/fmtvprint.c
@@ -0,0 +1,52 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+ va_list va;
+ int n;
+
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_COPY(va,f->args);
+ VA_END(f->args);
+ VA_COPY(f->args,args);
+ n = dofmt(f, fmt);
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ VA_END(f->args);
+ VA_COPY(f->args,va);
+ VA_END(va);
+ if(n >= 0)
+ return 0;
+ return n;
+}
+
diff --git a/src/lib9/fmt/fprint.c b/src/lib9/fmt/fprint.c
new file mode 100644
index 000000000..70cb1385a
--- /dev/null
+++ b/src/lib9/fmt/fprint.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+fprint(int fd, char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vfprint(fd, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/src/lib9/fmt/nan64.c b/src/lib9/fmt/nan64.c
new file mode 100644
index 000000000..1ea702741
--- /dev/null
+++ b/src/lib9/fmt/nan64.c
@@ -0,0 +1,93 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * 64-bit IEEE not-a-number routines.
+ * This is big/little-endian portable assuming that
+ * the 64-bit doubles and 64-bit integers have the
+ * same byte ordering.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001;
+static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000;
+static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
+
+/* gcc sees through the obvious casts. */
+static uvlong
+d2u(double d)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.d = d;
+ return u.v;
+}
+
+static double
+u2d(uvlong v)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.v = v;
+ return u.d;
+}
+
+double
+__NaN(void)
+{
+ return u2d(uvnan);
+}
+
+int
+__isNaN(double d)
+{
+ uvlong x;
+
+ x = d2u(d);
+ /* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
+ return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
+}
+
+double
+__Inf(int sign)
+{
+ return u2d(sign < 0 ? uvneginf : uvinf);
+}
+
+int
+__isInf(double d, int sign)
+{
+ uvlong x;
+
+ x = d2u(d);
+ if(sign == 0)
+ return x==uvinf || x==uvneginf;
+ else if(sign > 0)
+ return x==uvinf;
+ else
+ return x==uvneginf;
+}
diff --git a/src/lib9/fmt/pow10.c b/src/lib9/fmt/pow10.c
new file mode 100644
index 000000000..e146884a8
--- /dev/null
+++ b/src/lib9/fmt/pow10.c
@@ -0,0 +1,60 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+
+static
+double tab[] =
+{
+ 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
+ 1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
+ 1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
+ 1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
+ 1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
+ 1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
+ 1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
+};
+
+double
+__fmtpow10(int n)
+{
+ int m;
+
+ if(n < 0) {
+ n = -n;
+ if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+ return 1/tab[n];
+ m = n/2;
+ return __fmtpow10(-m) * __fmtpow10(m-n);
+ }
+ if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+ return tab[n];
+ m = n/2;
+ return __fmtpow10(m) * __fmtpow10(n-m);
+}
diff --git a/src/lib9/fmt/print.c b/src/lib9/fmt/print.c
new file mode 100644
index 000000000..5c39457d6
--- /dev/null
+++ b/src/lib9/fmt/print.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+print(char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vfprint(1, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/src/lib9/fmt/seprint.c b/src/lib9/fmt/seprint.c
new file mode 100644
index 000000000..88779d90a
--- /dev/null
+++ b/src/lib9/fmt/seprint.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+ char *p;
+ va_list args;
+
+ va_start(args, fmt);
+ p = vseprint(buf, e, fmt, args);
+ va_end(args);
+ return p;
+}
diff --git a/src/lib9/fmt/smprint.c b/src/lib9/fmt/smprint.c
new file mode 100644
index 000000000..c13ffd7dd
--- /dev/null
+++ b/src/lib9/fmt/smprint.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+smprint(char *fmt, ...)
+{
+ va_list args;
+ char *p;
+
+ va_start(args, fmt);
+ p = vsmprint(fmt, args);
+ va_end(args);
+ return p;
+}
diff --git a/src/lib9/fmt/snprint.c b/src/lib9/fmt/snprint.c
new file mode 100644
index 000000000..372399c44
--- /dev/null
+++ b/src/lib9/fmt/snprint.c
@@ -0,0 +1,34 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprint(buf, len, fmt, args);
+ va_end(args);
+ return n;
+}
+
diff --git a/src/lib9/fmt/sprint.c b/src/lib9/fmt/sprint.c
new file mode 100644
index 000000000..38d430744
--- /dev/null
+++ b/src/lib9/fmt/sprint.c
@@ -0,0 +1,45 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+sprint(char *buf, char *fmt, ...)
+{
+ int n;
+ uint len;
+ va_list args;
+
+ len = 1<<30; /* big number, but sprint is deprecated anyway */
+ /*
+ * on PowerPC, the stack is near the top of memory, so
+ * we must be sure not to overflow a 32-bit pointer.
+ *
+ * careful! gcc-4.2 assumes buf+len < buf can never be true and
+ * optimizes the test away. casting to uintptr works around this bug.
+ */
+ if((uintptr)buf+len < (uintptr)buf)
+ len = -(uintptr)buf-1;
+
+ va_start(args, fmt);
+ n = vsnprint(buf, len, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/src/lib9/fmt/test.c b/src/lib9/fmt/test.c
new file mode 100644
index 000000000..1710c5e48
--- /dev/null
+++ b/src/lib9/fmt/test.c
@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+main(int argc, char *argv[])
+{
+ quotefmtinstall();
+ print("hello world\n");
+ print("x: %x\n", 0x87654321);
+ print("u: %u\n", 0x87654321);
+ print("d: %d\n", 0x87654321);
+ print("s: %s\n", "hi there");
+ print("q: %q\n", "hi i'm here");
+ print("c: %c\n", '!');
+ print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
+ print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
+ print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
+ print("smiley: %C\n", (Rune)0x263a);
+ print("%g %.18g\n", 2e25, 2e25);
+ print("%2.18g\n", 1.0);
+ print("%2.18f\n", 1.0);
+ print("%f\n", 3.1415927/4);
+ print("%d\n", 23);
+ print("%i\n", 23);
+ print("%0.10d\n", 12345);
+
+ /* test %4$d formats */
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
+ print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
+ print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
+
+ /* test %'d formats */
+ print("%'d %'d %'d\n", 1, 2222, 33333333);
+ print("%'019d\n", 0);
+ print("%08d %08d %08d\n", 1, 2222, 33333333);
+ print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
+ print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
+ print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL);
+ return 0;
+}
diff --git a/src/lib9/fmt/vfprint.c b/src/lib9/fmt/vfprint.c
new file mode 100644
index 000000000..a23c5a0c6
--- /dev/null
+++ b/src/lib9/fmt/vfprint.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+vfprint(int fd, char *fmt, va_list args)
+{
+ Fmt f;
+ char buf[256];
+ int n;
+
+ fmtfdinit(&f, fd, buf, sizeof(buf));
+ VA_COPY(f.args,args);
+ n = dofmt(&f, fmt);
+ VA_END(f.args);
+ if(n > 0 && __fmtFdFlush(&f) == 0)
+ return -1;
+ return n;
+}
diff --git a/src/lib9/fmt/vseprint.c b/src/lib9/fmt/vseprint.c
new file mode 100644
index 000000000..c9fbfb956
--- /dev/null
+++ b/src/lib9/fmt/vseprint.c
@@ -0,0 +1,44 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+ Fmt f;
+
+ if(e <= buf)
+ return nil;
+ f.runes = 0;
+ f.start = buf;
+ f.to = buf;
+ f.stop = e - 1;
+ f.flush = 0;
+ f.farg = nil;
+ f.nfmt = 0;
+ VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
+ dofmt(&f, fmt);
+ VA_END(f.args);
+ *(char*)f.to = '\0';
+ return (char*)f.to;
+}
+
diff --git a/src/lib9/fmt/vsmprint.c b/src/lib9/fmt/vsmprint.c
new file mode 100644
index 000000000..4bd0bc4b7
--- /dev/null
+++ b/src/lib9/fmt/vsmprint.c
@@ -0,0 +1,87 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+ char *s;
+ int n;
+
+ if(f->start == nil)
+ return 0;
+ n = (uintptr)f->farg;
+ n *= 2;
+ s = (char*)f->start;
+ f->start = realloc(s, n);
+ if(f->start == nil){
+ f->farg = nil;
+ f->to = nil;
+ f->stop = nil;
+ free(s);
+ return 0;
+ }
+ f->farg = (void*)(uintptr)n;
+ f->to = (char*)f->start + ((char*)f->to - s);
+ f->stop = (char*)f->start + n - 1;
+ return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+ int n;
+
+ memset(f, 0, sizeof *f);
+ f->runes = 0;
+ n = 32;
+ f->start = malloc(n);
+ if(f->start == nil)
+ return -1;
+ f->to = f->start;
+ f->stop = (char*)f->start + n - 1;
+ f->flush = fmtStrFlush;
+ f->farg = (void*)(uintptr)n;
+ f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+ Fmt f;
+ int n;
+
+ if(fmtstrinit(&f) < 0)
+ return nil;
+ VA_COPY(f.args,args);
+ n = dofmt(&f, fmt);
+ VA_END(f.args);
+ if(n < 0){
+ free(f.start);
+ return nil;
+ }
+ return fmtstrflush(&f);
+}
diff --git a/src/lib9/fmt/vsnprint.c b/src/lib9/fmt/vsnprint.c
new file mode 100644
index 000000000..33d6bba4d
--- /dev/null
+++ b/src/lib9/fmt/vsnprint.c
@@ -0,0 +1,43 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+ Fmt f;
+
+ if(len <= 0)
+ return -1;
+ f.runes = 0;
+ f.start = buf;
+ f.to = buf;
+ f.stop = buf + len - 1;
+ f.flush = 0;
+ f.farg = nil;
+ f.nfmt = 0;
+ VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
+ dofmt(&f, fmt);
+ VA_END(f.args);
+ *(char*)f.to = '\0';
+ return (char*)f.to - buf;
+}
diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
new file mode 100644
index 000000000..75406b5d1
--- /dev/null
+++ b/src/lib9/fmtlock2.c
@@ -0,0 +1,38 @@
+/*
+Plan 9 from User Space src/lib9/fmtlock2.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/fmtlock2.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+Portions Copyright 2009 The Go Authors. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void
+__fmtlock(void)
+{
+}
+
+void
+__fmtunlock(void)
+{
+}
diff --git a/src/lib9/fork.c b/src/lib9/fork.c
new file mode 100644
index 000000000..0dd79dfb8
--- /dev/null
+++ b/src/lib9/fork.c
@@ -0,0 +1,46 @@
+/*
+Plan 9 from User Space src/lib9/fork.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/fork.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <signal.h>
+#include <libc.h>
+#include "9proc.h"
+#undef fork
+
+int
+p9fork(void)
+{
+ int pid;
+ sigset_t all, old;
+
+ sigfillset(&all);
+ sigprocmask(SIG_SETMASK, &all, &old);
+ pid = fork();
+ if(pid == 0){
+ _clearuproc();
+ _p9uproc(0);
+ }
+ sigprocmask(SIG_SETMASK, &old, nil);
+ return pid;
+}
diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
new file mode 100644
index 000000000..9d805b516
--- /dev/null
+++ b/src/lib9/getenv.c
@@ -0,0 +1,50 @@
+/*
+Plan 9 from User Space src/lib9/getenv.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getenv.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+char*
+p9getenv(char *s)
+{
+ char *t;
+
+ t = getenv(s);
+ if(t == 0)
+ return 0;
+ return strdup(t);
+}
+
+int
+p9putenv(char *s, char *v)
+{
+ char *t;
+
+ t = smprint("%s=%s", s, v);
+ if(t == nil)
+ return -1;
+ putenv(t);
+ return 0;
+}
diff --git a/src/lib9/getfields.c b/src/lib9/getfields.c
new file mode 100644
index 000000000..898328cb8
--- /dev/null
+++ b/src/lib9/getfields.c
@@ -0,0 +1,62 @@
+/*
+Inferno libkern/getfields.c
+http://code.google.com/p/inferno-os/source/browse/libkern/getfields.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <lib9.h>
+
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+ Rune r;
+ int nr, intok, narg;
+
+ if(max <= 0)
+ return 0;
+
+ narg = 0;
+ args[narg] = str;
+ if(!mflag)
+ narg++;
+ intok = 0;
+ for(;; str += nr) {
+ nr = chartorune(&r, str);
+ if(r == 0)
+ break;
+ if(utfrune(set, r)) {
+ if(narg >= max)
+ break;
+ *str = 0;
+ intok = 0;
+ args[narg] = str + nr;
+ if(!mflag)
+ narg++;
+ } else {
+ if(!intok && mflag)
+ narg++;
+ intok = 1;
+ }
+ }
+ return narg;
+}
diff --git a/src/lib9/getuser.c b/src/lib9/getuser.c
new file mode 100644
index 000000000..f70b35c87
--- /dev/null
+++ b/src/lib9/getuser.c
@@ -0,0 +1,41 @@
+/*
+Plan 9 from User Space src/lib9/getuser.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getuser.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <pwd.h>
+#include <libc.h>
+
+char*
+getuser(void)
+{
+ static char user[64];
+ struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if(pw == nil)
+ return "none";
+ strecpy(user, user+sizeof user, pw->pw_name);
+ return user;
+}
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
new file mode 100644
index 000000000..c3dd2b560
--- /dev/null
+++ b/src/lib9/getwd.c
@@ -0,0 +1,34 @@
+/*
+Plan 9 from User Space src/lib9/getwd.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getwd.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <libc.h>
+
+#undef getwd
+
+char*
+p9getwd(char *s, int ns)
+{
+ return getcwd(s, ns);
+}
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
new file mode 100644
index 000000000..a606fb07b
--- /dev/null
+++ b/src/lib9/jmp.c
@@ -0,0 +1,42 @@
+/*
+Plan 9 from User Space src/lib9/jmp.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/jmp.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+void
+p9longjmp(p9jmp_buf buf, int val)
+{
+ siglongjmp((void*)buf, val);
+}
+
+void
+p9notejmp(void *x, p9jmp_buf buf, int val)
+{
+ USED(x);
+ siglongjmp((void*)buf, val);
+}
+
diff --git a/src/lib9/main.c b/src/lib9/main.c
new file mode 100644
index 000000000..45f86c7ec
--- /dev/null
+++ b/src/lib9/main.c
@@ -0,0 +1,38 @@
+/*
+Plan 9 from User Space src/lib9/main.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/main.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+extern void p9main(int, char**);
+
+int
+main(int argc, char **argv)
+{
+ p9main(argc, argv);
+ exits("main");
+ return 99;
+}
diff --git a/src/lib9/nan.c b/src/lib9/nan.c
new file mode 100644
index 000000000..e79943219
--- /dev/null
+++ b/src/lib9/nan.c
@@ -0,0 +1,52 @@
+/*
+Plan 9 from User Space src/lib9/nan.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/nan.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+#include "fmt/nan.h"
+
+double
+NaN(void)
+{
+ return __NaN();
+}
+
+double
+Inf(int sign)
+{
+ return __Inf(sign);
+}
+
+int
+isNaN(double x)
+{
+ return __isNaN(x);
+}
+
+int
+isInf(double x, int sign)
+{
+ return __isInf(x, sign);
+}
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
new file mode 100644
index 000000000..84999b887
--- /dev/null
+++ b/src/lib9/notify.c
@@ -0,0 +1,297 @@
+/*
+Plan 9 from User Space src/lib9/notify.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+ * Signal handling for Plan 9 programs.
+ * We stubbornly use the strings from Plan 9 instead
+ * of the enumerated Unix constants.
+ * There are some weird translations. In particular,
+ * a "kill" note is the same as SIGTERM in Unix.
+ * There is no equivalent note to Unix's SIGKILL, since
+ * it's not a deliverable signal anyway.
+ *
+ * We do not handle SIGABRT or SIGSEGV, mainly because
+ * the thread library queues its notes for later, and we want
+ * to dump core with the state at time of delivery.
+ *
+ * We have to add some extra entry points to provide the
+ * ability to tweak which signals are deliverable and which
+ * are acted upon. Notifydisable and notifyenable play with
+ * the process signal mask. Notifyignore enables the signal
+ * but will not call notifyf when it comes in. This is occasionally
+ * useful.
+ */
+
+#include <u.h>
+#include <signal.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+extern char *_p9sigstr(int, char*);
+extern int _p9strsig(char*);
+
+typedef struct Sig Sig;
+struct Sig
+{
+ int sig; /* signal number */
+ int flags;
+};
+
+enum
+{
+ Restart = 1<<0,
+ Ignore = 1<<1
+};
+
+static Sig sigs[] = {
+ SIGHUP, 0,
+ SIGINT, 0,
+ SIGQUIT, 0,
+ SIGILL, 0,
+ SIGTRAP, 0,
+/* SIGABRT, 0, */
+#ifdef SIGEMT
+ SIGEMT, 0,
+#endif
+ SIGFPE, 0,
+ SIGBUS, 0,
+/* SIGSEGV, 0, */
+ SIGCHLD, Restart|Ignore,
+ SIGSYS, 0,
+ SIGPIPE, Ignore,
+ SIGALRM, 0,
+ SIGTERM, 0,
+ SIGTSTP, Restart|Ignore,
+/* SIGTTIN, Restart|Ignore, */
+/* SIGTTOU, Restart|Ignore, */
+ SIGXCPU, 0,
+ SIGXFSZ, 0,
+ SIGVTALRM, 0,
+ SIGUSR1, 0,
+ SIGUSR2, 0,
+#ifdef SIGWINCH
+ SIGWINCH, Restart|Ignore,
+#endif
+#ifdef SIGINFO
+ SIGINFO, Restart|Ignore,
+#endif
+};
+
+static Sig*
+findsig(int s)
+{
+ int i;
+
+ for(i=0; i<nelem(sigs); i++)
+ if(sigs[i].sig == s)
+ return &sigs[i];
+ return nil;
+}
+
+/*
+ * The thread library initializes _notejmpbuf to its own
+ * routine which provides a per-pthread jump buffer.
+ * If we're not using the thread library, we assume we are
+ * single-threaded.
+ */
+typedef struct Jmp Jmp;
+struct Jmp
+{
+ p9jmp_buf b;
+};
+
+static Jmp onejmp;
+
+static Jmp*
+getonejmp(void)
+{
+ return &onejmp;
+}
+
+Jmp *(*_notejmpbuf)(void) = getonejmp;
+static void noteinit(void);
+
+/*
+ * Actual signal handler.
+ */
+
+static void (*notifyf)(void*, char*); /* Plan 9 handler */
+
+static void
+signotify(int sig)
+{
+ char tmp[64];
+ Jmp *j;
+ Sig *s;
+
+ j = (*_notejmpbuf)();
+ switch(p9setjmp(j->b)){
+ case 0:
+ if(notifyf)
+ (*notifyf)(nil, _p9sigstr(sig, tmp));
+ /* fall through */
+ case 1: /* noted(NDFLT) */
+ if(0)print("DEFAULT %d\n", sig);
+ s = findsig(sig);
+ if(s && (s->flags&Ignore))
+ return;
+ signal(sig, SIG_DFL);
+ raise(sig);
+ _exit(1);
+ case 2: /* noted(NCONT) */
+ if(0)print("HANDLED %d\n", sig);
+ return;
+ }
+}
+
+static void
+signonotify(int sig)
+{
+ USED(sig);
+}
+
+int
+noted(int v)
+{
+ p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
+ abort();
+ return 0;
+}
+
+int
+notify(void (*f)(void*, char*))
+{
+ static int init;
+
+ notifyf = f;
+ if(!init){
+ init = 1;
+ noteinit();
+ }
+ return 0;
+}
+
+/*
+ * Nonsense about enabling and disabling signals.
+ */
+typedef void Sighandler(int);
+static Sighandler*
+handler(int s)
+{
+ struct sigaction sa;
+
+ sigaction(s, nil, &sa);
+ return sa.sa_handler;
+}
+
+static int
+notesetenable(int sig, int enabled)
+{
+ sigset_t mask, omask;
+
+ if(sig == 0)
+ return -1;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, sig);
+ sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
+ return !sigismember(&omask, sig);
+}
+
+int
+noteenable(char *msg)
+{
+ return notesetenable(_p9strsig(msg), 1);
+}
+
+int
+notedisable(char *msg)
+{
+ return notesetenable(_p9strsig(msg), 0);
+}
+
+static int
+notifyseton(int s, int on)
+{
+ Sig *sig;
+ struct sigaction sa, osa;
+
+ sig = findsig(s);
+ if(sig == nil)
+ return -1;
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = on ? signotify : signonotify;
+ if(sig->flags&Restart)
+ sa.sa_flags |= SA_RESTART;
+
+ /*
+ * We can't allow signals within signals because there's
+ * only one jump buffer.
+ */
+ sigfillset(&sa.sa_mask);
+
+ /*
+ * Install handler.
+ */
+ sigaction(sig->sig, &sa, &osa);
+ return osa.sa_handler == signotify;
+}
+
+int
+notifyon(char *msg)
+{
+ return notifyseton(_p9strsig(msg), 1);
+}
+
+int
+notifyoff(char *msg)
+{
+ return notifyseton(_p9strsig(msg), 0);
+}
+
+/*
+ * Initialization follows sigs table.
+ */
+static void
+noteinit(void)
+{
+ int i;
+ Sig *sig;
+
+ for(i=0; i<nelem(sigs); i++){
+ sig = &sigs[i];
+ /*
+ * If someone has already installed a handler,
+ * It's probably some ld preload nonsense,
+ * like pct (a SIGVTALRM-based profiler).
+ * Or maybe someone has already called notifyon/notifyoff.
+ * Leave it alone.
+ */
+ if(handler(sig->sig) != SIG_DFL)
+ continue;
+ notifyseton(sig->sig, 1);
+ }
+}
+
diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
new file mode 100644
index 000000000..aa1a1232e
--- /dev/null
+++ b/src/lib9/nulldir.c
@@ -0,0 +1,35 @@
+/*
+Inferno lib9/nulldir.c
+http://code.google.com/p/inferno-os/source/browse/lib9/nulldir.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void
+nulldir(Dir *d)
+{
+ memset(d, ~0, sizeof(Dir));
+ d->name = d->uid = d->gid = d->muid = "";
+}
diff --git a/src/lib9/open.c b/src/lib9/open.c
new file mode 100644
index 000000000..1fa3c1bc7
--- /dev/null
+++ b/src/lib9/open.c
@@ -0,0 +1,87 @@
+/*
+Plan 9 from User Space src/lib9/open.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/open.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define _GNU_SOURCE /* for Linux O_DIRECT */
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <sys/file.h>
+#include <libc.h>
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+int
+p9open(char *name, int mode)
+{
+ int cexec, rclose;
+ int fd, umode, lock, rdwr;
+ struct flock fl;
+
+ rdwr = mode&3;
+ umode = rdwr;
+ cexec = mode&OCEXEC;
+ rclose = mode&ORCLOSE;
+ lock = mode&OLOCK;
+ mode &= ~(3|OCEXEC|ORCLOSE|OLOCK);
+ if(mode&OTRUNC){
+ umode |= O_TRUNC;
+ mode ^= OTRUNC;
+ }
+ if(mode&ODIRECT){
+ umode |= O_DIRECT;
+ mode ^= ODIRECT;
+ }
+ if(mode&ONONBLOCK){
+ umode |= O_NONBLOCK;
+ mode ^= ONONBLOCK;
+ }
+ if(mode&OAPPEND){
+ umode |= O_APPEND;
+ mode ^= OAPPEND;
+ }
+ if(mode){
+ werrstr("mode 0x%x not supported", mode);
+ return -1;
+ }
+ fd = open(name, umode);
+ if(fd >= 0){
+ if(lock){
+ fl.l_type = (rdwr==OREAD) ? F_RDLCK : F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ if(fcntl(fd, F_SETLK, &fl) < 0){
+ close(fd);
+ werrstr("lock: %r");
+ return -1;
+ }
+ }
+ if(cexec)
+ fcntl(fd, F_SETFL, FD_CLOEXEC);
+ if(rclose)
+ remove(name);
+ }
+ return fd;
+}
diff --git a/src/lib9/pipe.c b/src/lib9/pipe.c
new file mode 100644
index 000000000..0a7d07390
--- /dev/null
+++ b/src/lib9/pipe.c
@@ -0,0 +1,39 @@
+/*
+Plan 9 from User Space src/lib9/getenv.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getenv.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include <sys/socket.h>
+
+/*
+ * We use socketpair to get a two-way pipe.
+ * The pipe still doesn't preserve message boundaries.
+ * Worse, it cannot be reopened via /dev/fd/NNN on Linux.
+ */
+int
+p9pipe(int fd[2])
+{
+ return socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
+}
diff --git a/src/lib9/readn.c b/src/lib9/readn.c
new file mode 100644
index 000000000..76e497de8
--- /dev/null
+++ b/src/lib9/readn.c
@@ -0,0 +1,47 @@
+/*
+Inferno lib9/readn.c
+http://code.google.com/p/inferno-os/source/browse/lib9/readn.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <lib9.h>
+
+long
+readn(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = read(f, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
new file mode 100644
index 000000000..c9d632189
--- /dev/null
+++ b/src/lib9/rfork.c
@@ -0,0 +1,153 @@
+/*
+Plan 9 from User Space src/lib9/rfork.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/rfork.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <libc.h>
+#undef rfork
+
+static void
+nop(int x)
+{
+ USED(x);
+}
+
+int
+p9rfork(int flags)
+{
+ int pid, status;
+ int p[2];
+ int n;
+ char buf[128], *q;
+ extern char **environ;
+
+ if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
+ /* check other flags before we commit */
+ flags &= ~(RFPROC|RFFDG|RFENVG);
+ n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
+ if(n){
+ werrstr("unknown flags %08ux in rfork", n);
+ return -1;
+ }
+ if(flags&RFNOWAIT){
+ /*
+ * BUG - should put the signal handler back after we
+ * finish, but I just don't care. If a program calls with
+ * NOWAIT once, they're not likely to want child notes
+ * after that.
+ */
+ signal(SIGCHLD, nop);
+ if(pipe(p) < 0)
+ return -1;
+ }
+ pid = fork();
+ if(pid == -1)
+ return -1;
+ if(flags&RFNOWAIT){
+ flags &= ~RFNOWAIT;
+ if(pid){
+ /*
+ * Parent - wait for child to fork wait-free child.
+ * Then read pid from pipe. Assume pipe buffer can absorb the write.
+ */
+ close(p[1]);
+ status = 0;
+ if(wait4(pid, &status, 0, 0) < 0){
+ werrstr("pipe dance - wait4 - %r");
+ close(p[0]);
+ return -1;
+ }
+ n = readn(p[0], buf, sizeof buf-1);
+ close(p[0]);
+ if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
+ if(!WIFEXITED(status))
+ werrstr("pipe dance - !exited 0x%ux", status);
+ else if(WEXITSTATUS(status) != 0)
+ werrstr("pipe dance - non-zero status 0x%ux", status);
+ else if(n < 0)
+ werrstr("pipe dance - pipe read error - %r");
+ else if(n == 0)
+ werrstr("pipe dance - pipe read eof");
+ else
+ werrstr("pipe dance - unknown failure");
+ return -1;
+ }
+ buf[n] = 0;
+ if(buf[0] == 'x'){
+ werrstr("%s", buf+2);
+ return -1;
+ }
+ pid = strtol(buf, &q, 0);
+ }else{
+ /*
+ * Child - fork a new child whose wait message can't
+ * get back to the parent because we're going to exit!
+ */
+ signal(SIGCHLD, SIG_IGN);
+ close(p[0]);
+ pid = fork();
+ if(pid){
+ /* Child parent - send status over pipe and exit. */
+ if(pid > 0)
+ fprint(p[1], "%d", pid);
+ else
+ fprint(p[1], "x %r");
+ close(p[1]);
+ _exit(0);
+ }else{
+ /* Child child - close pipe. */
+ close(p[1]);
+ }
+ }
+ }
+ if(pid != 0)
+ return pid;
+ if(flags&RFCENVG)
+ if(environ)
+ *environ = nil;
+ }
+ if(flags&RFPROC){
+ werrstr("cannot use rfork for shared memory -- use libthread");
+ return -1;
+ }
+ if(flags&RFNAMEG){
+ /* XXX set $NAMESPACE to a new directory */
+ flags &= ~RFNAMEG;
+ }
+ if(flags&RFNOTEG){
+ setpgid(0, getpid());
+ flags &= ~RFNOTEG;
+ }
+ if(flags&RFNOWAIT){
+ werrstr("cannot use RFNOWAIT without RFPROC");
+ return -1;
+ }
+ if(flags){
+ werrstr("unknown flags %08ux in rfork", flags);
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/lib9/seek.c b/src/lib9/seek.c
new file mode 100644
index 000000000..917003808
--- /dev/null
+++ b/src/lib9/seek.c
@@ -0,0 +1,33 @@
+/*
+Plan 9 from User Space src/lib9/seek.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/seek.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+vlong
+seek(int fd, vlong offset, int whence)
+{
+ return lseek(fd, offset, whence);
+}
diff --git a/src/lib9/strecpy.c b/src/lib9/strecpy.c
new file mode 100644
index 000000000..f38b524c2
--- /dev/null
+++ b/src/lib9/strecpy.c
@@ -0,0 +1,42 @@
+/*
+Inferno lib9/strecpy.c
+http://code.google.com/p/inferno-os/source/browse/lib9/strecpy.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <lib9.h>
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+ if(to >= e)
+ return to;
+ to = memccpy(to, from, '\0', e - to);
+ if(to == nil){
+ to = e - 1;
+ *to = '\0';
+ }else{
+ to--;
+ }
+ return to;
+}
diff --git a/src/lib9/sysfatal.c b/src/lib9/sysfatal.c
new file mode 100644
index 000000000..a5af3e1b4
--- /dev/null
+++ b/src/lib9/sysfatal.c
@@ -0,0 +1,47 @@
+/*
+Plan 9 from User Space src/lib9/sysfatal.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/sysfatal.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <u.h>
+#include <libc.h>
+
+void (*_sysfatal)(char*, ...);
+
+void
+sysfatal(char *fmt, ...)
+{
+ char buf[256];
+ va_list arg;
+
+ va_start(arg, fmt);
+ if(_sysfatal)
+ (*_sysfatal)(fmt, arg);
+ vseprint(buf, buf+sizeof buf, fmt, arg);
+ va_end(arg);
+
+ __fixargv0();
+ fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
+ exits("fatal");
+}
+
diff --git a/src/lib9/tokenize.c b/src/lib9/tokenize.c
new file mode 100644
index 000000000..6b8c0e778
--- /dev/null
+++ b/src/lib9/tokenize.c
@@ -0,0 +1,132 @@
+/*
+Inferno lib9/tokenize.c
+http://code.google.com/p/inferno-os/source/browse/lib9/tokenize.c
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <lib9.h>
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+ int quoting;
+ char *t;
+
+ quoting = 0;
+ t = s; /* s is output string, t is input string */
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ *s++ = *t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t++;
+ *s++ = *t++;
+ }
+ if(*s != '\0'){
+ *s = '\0';
+ if(t == s)
+ t++;
+ }
+ return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+ int quoting;
+
+ /* move to end of next token */
+ quoting = 0;
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t += 2;
+ }
+ return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(sep, *s)!=nil)
+ *s++ = '\0';
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = etoken(s, sep);
+ }
+
+ return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(qsep, *s)!=nil)
+ s++;
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = qtoken(s, qsep);
+ }
+
+ return nargs;
+}
diff --git a/src/lib9/utf/rune.c b/src/lib9/utf/rune.c
new file mode 100644
index 000000000..3d6831b02
--- /dev/null
+++ b/src/lib9/utf/rune.c
@@ -0,0 +1,177 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+
+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
+
+ Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
+ Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
+ Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Bad = Runeerror
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+ int c, c1, c2;
+ long l;
+
+ /*
+ * one character sequence
+ * 00000-0007F => T1
+ */
+ c = *(uchar*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uchar*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uchar*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+ long c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = *rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ str[1] = Tx | (c & Maskx);
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ str[0] = T3 | (c >> 2*Bitx);
+ str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[2] = Tx | (c & Maskx);
+ return 3;
+}
+
+int
+runelen(long c)
+{
+ Rune rune;
+ char str[10];
+
+ rune = c;
+ return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+ int nb, c;
+
+ nb = 0;
+ while(nrune--) {
+ c = *r++;
+ if(c <= Rune1)
+ nb++;
+ else
+ if(c <= Rune2)
+ nb += 2;
+ else
+ nb += 3;
+ }
+ return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+ int c;
+
+ if(n > 0) {
+ c = *(uchar*)str;
+ if(c < Tx)
+ return 1;
+ if(n > 1)
+ if(c < T3 || n > 2)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
new file mode 100644
index 000000000..ac6d7b576
--- /dev/null
+++ b/src/lib9/utf/runetype.c
@@ -0,0 +1,1151 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+/*
+ * alpha ranges -
+ * only covers ranges not in lower||upper
+ */
+static
+Rune __alpha2[] =
+{
+ 0x00d8, 0x00f6, /* Ø - ö */
+ 0x00f8, 0x01f5, /* ø - ǵ */
+ 0x0250, 0x02a8, /* ɐ - ʨ */
+ 0x038e, 0x03a1, /* Ύ - Ρ */
+ 0x03a3, 0x03ce, /* Σ - ώ */
+ 0x03d0, 0x03d6, /* ϐ - ϖ */
+ 0x03e2, 0x03f3, /* Ϣ - ϳ */
+ 0x0490, 0x04c4, /* Ґ - ӄ */
+ 0x0561, 0x0587, /* ա - և */
+ 0x05d0, 0x05ea, /* א - ת */
+ 0x05f0, 0x05f2, /* װ - ײ */
+ 0x0621, 0x063a, /* ء - غ */
+ 0x0640, 0x064a, /* ـ - ي */
+ 0x0671, 0x06b7, /* ٱ - ڷ */
+ 0x06ba, 0x06be, /* ں - ھ */
+ 0x06c0, 0x06ce, /* ۀ - ێ */
+ 0x06d0, 0x06d3, /* ې - ۓ */
+ 0x0905, 0x0939, /* अ - ह */
+ 0x0958, 0x0961, /* क़ - ॡ */
+ 0x0985, 0x098c, /* অ - ঌ */
+ 0x098f, 0x0990, /* এ - ঐ */
+ 0x0993, 0x09a8, /* ও - ন */
+ 0x09aa, 0x09b0, /* প - র */
+ 0x09b6, 0x09b9, /* শ - হ */
+ 0x09dc, 0x09dd, /* ড় - ঢ় */
+ 0x09df, 0x09e1, /* য় - ৡ */
+ 0x09f0, 0x09f1, /* ৰ - ৱ */
+ 0x0a05, 0x0a0a, /* ਅ - ਊ */
+ 0x0a0f, 0x0a10, /* ਏ - ਐ */
+ 0x0a13, 0x0a28, /* ਓ - ਨ */
+ 0x0a2a, 0x0a30, /* ਪ - ਰ */
+ 0x0a32, 0x0a33, /* ਲ - ਲ਼ */
+ 0x0a35, 0x0a36, /* ਵ - ਸ਼ */
+ 0x0a38, 0x0a39, /* ਸ - ਹ */
+ 0x0a59, 0x0a5c, /* ਖ਼ - ੜ */
+ 0x0a85, 0x0a8b, /* અ - ઋ */
+ 0x0a8f, 0x0a91, /* એ - ઑ */
+ 0x0a93, 0x0aa8, /* ઓ - ન */
+ 0x0aaa, 0x0ab0, /* પ - ર */
+ 0x0ab2, 0x0ab3, /* લ - ળ */
+ 0x0ab5, 0x0ab9, /* વ - હ */
+ 0x0b05, 0x0b0c, /* ଅ - ଌ */
+ 0x0b0f, 0x0b10, /* ଏ - ଐ */
+ 0x0b13, 0x0b28, /* ଓ - ନ */
+ 0x0b2a, 0x0b30, /* ପ - ର */
+ 0x0b32, 0x0b33, /* ଲ - ଳ */
+ 0x0b36, 0x0b39, /* ଶ - ହ */
+ 0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */
+ 0x0b5f, 0x0b61, /* ୟ - ୡ */
+ 0x0b85, 0x0b8a, /* அ - ஊ */
+ 0x0b8e, 0x0b90, /* எ - ஐ */
+ 0x0b92, 0x0b95, /* ஒ - க */
+ 0x0b99, 0x0b9a, /* ங - ச */
+ 0x0b9e, 0x0b9f, /* ஞ - ட */
+ 0x0ba3, 0x0ba4, /* ண - த */
+ 0x0ba8, 0x0baa, /* ந - ப */
+ 0x0bae, 0x0bb5, /* ம - வ */
+ 0x0bb7, 0x0bb9, /* ஷ - ஹ */
+ 0x0c05, 0x0c0c, /* అ - ఌ */
+ 0x0c0e, 0x0c10, /* ఎ - ఐ */
+ 0x0c12, 0x0c28, /* ఒ - న */
+ 0x0c2a, 0x0c33, /* ప - ళ */
+ 0x0c35, 0x0c39, /* వ - హ */
+ 0x0c60, 0x0c61, /* ౠ - ౡ */
+ 0x0c85, 0x0c8c, /* ಅ - ಌ */
+ 0x0c8e, 0x0c90, /* ಎ - ಐ */
+ 0x0c92, 0x0ca8, /* ಒ - ನ */
+ 0x0caa, 0x0cb3, /* ಪ - ಳ */
+ 0x0cb5, 0x0cb9, /* ವ - ಹ */
+ 0x0ce0, 0x0ce1, /* ೠ - ೡ */
+ 0x0d05, 0x0d0c, /* അ - ഌ */
+ 0x0d0e, 0x0d10, /* എ - ഐ */
+ 0x0d12, 0x0d28, /* ഒ - ന */
+ 0x0d2a, 0x0d39, /* പ - ഹ */
+ 0x0d60, 0x0d61, /* ൠ - ൡ */
+ 0x0e01, 0x0e30, /* ก - ะ */
+ 0x0e32, 0x0e33, /* า - ำ */
+ 0x0e40, 0x0e46, /* เ - ๆ */
+ 0x0e5a, 0x0e5b, /* ๚ - ๛ */
+ 0x0e81, 0x0e82, /* ກ - ຂ */
+ 0x0e87, 0x0e88, /* ງ - ຈ */
+ 0x0e94, 0x0e97, /* ດ - ທ */
+ 0x0e99, 0x0e9f, /* ນ - ຟ */
+ 0x0ea1, 0x0ea3, /* ມ - ຣ */
+ 0x0eaa, 0x0eab, /* ສ - ຫ */
+ 0x0ead, 0x0eae, /* ອ - ຮ */
+ 0x0eb2, 0x0eb3, /* າ - ຳ */
+ 0x0ec0, 0x0ec4, /* ເ - ໄ */
+ 0x0edc, 0x0edd, /* ໜ - ໝ */
+ 0x0f18, 0x0f19, /* ༘ - ༙ */
+ 0x0f40, 0x0f47, /* ཀ - ཇ */
+ 0x0f49, 0x0f69, /* ཉ - ཀྵ */
+ 0x10d0, 0x10f6, /* ა - ჶ */
+ 0x1100, 0x1159, /* ᄀ - ᅙ */
+ 0x115f, 0x11a2, /* ᅟ - ᆢ */
+ 0x11a8, 0x11f9, /* ᆨ - ᇹ */
+ 0x1e00, 0x1e9b, /* Ḁ - ẛ */
+ 0x1f50, 0x1f57, /* ὐ - ὗ */
+ 0x1f80, 0x1fb4, /* ᾀ - ᾴ */
+ 0x1fb6, 0x1fbc, /* ᾶ - ᾼ */
+ 0x1fc2, 0x1fc4, /* ῂ - ῄ */
+ 0x1fc6, 0x1fcc, /* ῆ - ῌ */
+ 0x1fd0, 0x1fd3, /* ῐ - ΐ */
+ 0x1fd6, 0x1fdb, /* ῖ - Ί */
+ 0x1fe0, 0x1fec, /* ῠ - Ῥ */
+ 0x1ff2, 0x1ff4, /* ῲ - ῴ */
+ 0x1ff6, 0x1ffc, /* ῶ - ῼ */
+ 0x210a, 0x2113, /* ℊ - ℓ */
+ 0x2115, 0x211d, /* ℕ - ℝ */
+ 0x2120, 0x2122, /* ℠ - ™ */
+ 0x212a, 0x2131, /* K - ℱ */
+ 0x2133, 0x2138, /* ℳ - ℸ */
+ 0x3041, 0x3094, /* ぁ - ゔ */
+ 0x30a1, 0x30fa, /* ァ - ヺ */
+ 0x3105, 0x312c, /* ㄅ - ㄬ */
+ 0x3131, 0x318e, /* ㄱ - ㆎ */
+ 0x3192, 0x319f, /* ㆒ - ㆟ */
+ 0x3260, 0x327b, /* ㉠ - ㉻ */
+ 0x328a, 0x32b0, /* ㊊ - ㊰ */
+ 0x32d0, 0x32fe, /* ㋐ - ㋾ */
+ 0x3300, 0x3357, /* ㌀ - ㍗ */
+ 0x3371, 0x3376, /* ㍱ - ㍶ */
+ 0x337b, 0x3394, /* ㍻ - ㎔ */
+ 0x3399, 0x339e, /* ㎙ - ㎞ */
+ 0x33a9, 0x33ad, /* ㎩ - ㎭ */
+ 0x33b0, 0x33c1, /* ㎰ - ㏁ */
+ 0x33c3, 0x33c5, /* ㏃ - ㏅ */
+ 0x33c7, 0x33d7, /* ㏇ - ㏗ */
+ 0x33d9, 0x33dd, /* ㏙ - ㏝ */
+ 0x4e00, 0x9fff, /* 一 - 鿿 */
+ 0xac00, 0xd7a3, /* 가 - 힣 */
+ 0xf900, 0xfb06, /* 豈 - st */
+ 0xfb13, 0xfb17, /* ﬓ - ﬗ */
+ 0xfb1f, 0xfb28, /* ײַ - ﬨ */
+ 0xfb2a, 0xfb36, /* שׁ - זּ */
+ 0xfb38, 0xfb3c, /* טּ - לּ */
+ 0xfb40, 0xfb41, /* נּ - סּ */
+ 0xfb43, 0xfb44, /* ףּ - פּ */
+ 0xfb46, 0xfbb1, /* צּ - ﮱ */
+ 0xfbd3, 0xfd3d, /* ﯓ - ﴽ */
+ 0xfd50, 0xfd8f, /* ﵐ - ﶏ */
+ 0xfd92, 0xfdc7, /* ﶒ - ﷇ */
+ 0xfdf0, 0xfdf9, /* ﷰ - ﷹ */
+ 0xfe70, 0xfe72, /* ﹰ - ﹲ */
+ 0xfe76, 0xfefc, /* ﹶ - ﻼ */
+ 0xff66, 0xff6f, /* ヲ - ッ */
+ 0xff71, 0xff9d, /* ア - ン */
+ 0xffa0, 0xffbe, /* ᅠ - ᄒ */
+ 0xffc2, 0xffc7, /* ᅡ - ᅦ */
+ 0xffca, 0xffcf, /* ᅧ - ᅬ */
+ 0xffd2, 0xffd7, /* ᅭ - ᅲ */
+ 0xffda, 0xffdc, /* ᅳ - ᅵ */
+};
+
+/*
+ * alpha singlets -
+ * only covers ranges not in lower||upper
+ */
+static
+Rune __alpha1[] =
+{
+ 0x00aa, /* ª */
+ 0x00b5, /* µ */
+ 0x00ba, /* º */
+ 0x03da, /* Ϛ */
+ 0x03dc, /* Ϝ */
+ 0x03de, /* Ϟ */
+ 0x03e0, /* Ϡ */
+ 0x06d5, /* ە */
+ 0x09b2, /* ল */
+ 0x0a5e, /* ਫ਼ */
+ 0x0a8d, /* ઍ */
+ 0x0ae0, /* ૠ */
+ 0x0b9c, /* ஜ */
+ 0x0cde, /* ೞ */
+ 0x0e4f, /* ๏ */
+ 0x0e84, /* ຄ */
+ 0x0e8a, /* ຊ */
+ 0x0e8d, /* ຍ */
+ 0x0ea5, /* ລ */
+ 0x0ea7, /* ວ */
+ 0x0eb0, /* ະ */
+ 0x0ebd, /* ຽ */
+ 0x1fbe, /* ι */
+ 0x207f, /* ⁿ */
+ 0x20a8, /* ₨ */
+ 0x2102, /* ℂ */
+ 0x2107, /* ℇ */
+ 0x2124, /* ℤ */
+ 0x2126, /* Ω */
+ 0x2128, /* ℨ */
+ 0xfb3e, /* מּ */
+ 0xfe74, /* ﹴ */
+};
+
+/*
+ * space ranges
+ */
+static
+Rune __space2[] =
+{
+ 0x0009, 0x000a, /* tab and newline */
+ 0x0020, 0x0020, /* space */
+ 0x00a0, 0x00a0, /*   */
+ 0x2000, 0x200b, /*   - ​ */
+ 0x2028, 0x2029, /* 
 - 
 */
+ 0x3000, 0x3000, /*   */
+ 0xfeff, 0xfeff, /*  */
+};
+
+/*
+ * lower case ranges
+ * 3rd col is conversion excess 500
+ */
+static
+Rune __toupper2[] =
+{
+ 0x0061, 0x007a, 468, /* a-z A-Z */
+ 0x00e0, 0x00f6, 468, /* à-ö À-Ö */
+ 0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */
+ 0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */
+ 0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */
+ 0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */
+ 0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */
+ 0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */
+ 0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */
+ 0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */
+ 0x0430, 0x044f, 468, /* а-я А-Я */
+ 0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */
+ 0x045e, 0x045f, 420, /* ў-џ Ў-Џ */
+ 0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */
+ 0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */
+ 0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */
+ 0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */
+ 0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */
+ 0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */
+ 0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */
+ 0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */
+ 0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */
+ 0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */
+ 0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */
+ 0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */
+ 0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */
+ 0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */
+ 0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */
+ 0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */
+ 0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */
+ 0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */
+ 0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */
+ 0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */
+ 0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */
+ 0xff41, 0xff5a, 468, /* a-z A-Z */
+};
+
+/*
+ * lower case singlets
+ * 2nd col is conversion excess 500
+ */
+static
+Rune __toupper1[] =
+{
+ 0x00ff, 621, /* ÿ Ÿ */
+ 0x0101, 499, /* ā Ā */
+ 0x0103, 499, /* ă Ă */
+ 0x0105, 499, /* ą Ą */
+ 0x0107, 499, /* ć Ć */
+ 0x0109, 499, /* ĉ Ĉ */
+ 0x010b, 499, /* ċ Ċ */
+ 0x010d, 499, /* č Č */
+ 0x010f, 499, /* ď Ď */
+ 0x0111, 499, /* đ Đ */
+ 0x0113, 499, /* ē Ē */
+ 0x0115, 499, /* ĕ Ĕ */
+ 0x0117, 499, /* ė Ė */
+ 0x0119, 499, /* ę Ę */
+ 0x011b, 499, /* ě Ě */
+ 0x011d, 499, /* ĝ Ĝ */
+ 0x011f, 499, /* ğ Ğ */
+ 0x0121, 499, /* ġ Ġ */
+ 0x0123, 499, /* ģ Ģ */
+ 0x0125, 499, /* ĥ Ĥ */
+ 0x0127, 499, /* ħ Ħ */
+ 0x0129, 499, /* ĩ Ĩ */
+ 0x012b, 499, /* ī Ī */
+ 0x012d, 499, /* ĭ Ĭ */
+ 0x012f, 499, /* į Į */
+ 0x0131, 268, /* ı I */
+ 0x0133, 499, /* ij IJ */
+ 0x0135, 499, /* ĵ Ĵ */
+ 0x0137, 499, /* ķ Ķ */
+ 0x013a, 499, /* ĺ Ĺ */
+ 0x013c, 499, /* ļ Ļ */
+ 0x013e, 499, /* ľ Ľ */
+ 0x0140, 499, /* ŀ Ŀ */
+ 0x0142, 499, /* ł Ł */
+ 0x0144, 499, /* ń Ń */
+ 0x0146, 499, /* ņ Ņ */
+ 0x0148, 499, /* ň Ň */
+ 0x014b, 499, /* ŋ Ŋ */
+ 0x014d, 499, /* ō Ō */
+ 0x014f, 499, /* ŏ Ŏ */
+ 0x0151, 499, /* ő Ő */
+ 0x0153, 499, /* œ Œ */
+ 0x0155, 499, /* ŕ Ŕ */
+ 0x0157, 499, /* ŗ Ŗ */
+ 0x0159, 499, /* ř Ř */
+ 0x015b, 499, /* ś Ś */
+ 0x015d, 499, /* ŝ Ŝ */
+ 0x015f, 499, /* ş Ş */
+ 0x0161, 499, /* š Š */
+ 0x0163, 499, /* ţ Ţ */
+ 0x0165, 499, /* ť Ť */
+ 0x0167, 499, /* ŧ Ŧ */
+ 0x0169, 499, /* ũ Ũ */
+ 0x016b, 499, /* ū Ū */
+ 0x016d, 499, /* ŭ Ŭ */
+ 0x016f, 499, /* ů Ů */
+ 0x0171, 499, /* ű Ű */
+ 0x0173, 499, /* ų Ų */
+ 0x0175, 499, /* ŵ Ŵ */
+ 0x0177, 499, /* ŷ Ŷ */
+ 0x017a, 499, /* ź Ź */
+ 0x017c, 499, /* ż Ż */
+ 0x017e, 499, /* ž Ž */
+ 0x017f, 200, /* ſ S */
+ 0x0183, 499, /* ƃ Ƃ */
+ 0x0185, 499, /* ƅ Ƅ */
+ 0x0188, 499, /* ƈ Ƈ */
+ 0x018c, 499, /* ƌ Ƌ */
+ 0x0192, 499, /* ƒ Ƒ */
+ 0x0199, 499, /* ƙ Ƙ */
+ 0x01a1, 499, /* ơ Ơ */
+ 0x01a3, 499, /* ƣ Ƣ */
+ 0x01a5, 499, /* ƥ Ƥ */
+ 0x01a8, 499, /* ƨ Ƨ */
+ 0x01ad, 499, /* ƭ Ƭ */
+ 0x01b0, 499, /* ư Ư */
+ 0x01b4, 499, /* ƴ Ƴ */
+ 0x01b6, 499, /* ƶ Ƶ */
+ 0x01b9, 499, /* ƹ Ƹ */
+ 0x01bd, 499, /* ƽ Ƽ */
+ 0x01c5, 499, /* Dž DŽ */
+ 0x01c6, 498, /* dž DŽ */
+ 0x01c8, 499, /* Lj LJ */
+ 0x01c9, 498, /* lj LJ */
+ 0x01cb, 499, /* Nj NJ */
+ 0x01cc, 498, /* nj NJ */
+ 0x01ce, 499, /* ǎ Ǎ */
+ 0x01d0, 499, /* ǐ Ǐ */
+ 0x01d2, 499, /* ǒ Ǒ */
+ 0x01d4, 499, /* ǔ Ǔ */
+ 0x01d6, 499, /* ǖ Ǖ */
+ 0x01d8, 499, /* ǘ Ǘ */
+ 0x01da, 499, /* ǚ Ǚ */
+ 0x01dc, 499, /* ǜ Ǜ */
+ 0x01df, 499, /* ǟ Ǟ */
+ 0x01e1, 499, /* ǡ Ǡ */
+ 0x01e3, 499, /* ǣ Ǣ */
+ 0x01e5, 499, /* ǥ Ǥ */
+ 0x01e7, 499, /* ǧ Ǧ */
+ 0x01e9, 499, /* ǩ Ǩ */
+ 0x01eb, 499, /* ǫ Ǫ */
+ 0x01ed, 499, /* ǭ Ǭ */
+ 0x01ef, 499, /* ǯ Ǯ */
+ 0x01f2, 499, /* Dz DZ */
+ 0x01f3, 498, /* dz DZ */
+ 0x01f5, 499, /* ǵ Ǵ */
+ 0x01fb, 499, /* ǻ Ǻ */
+ 0x01fd, 499, /* ǽ Ǽ */
+ 0x01ff, 499, /* ǿ Ǿ */
+ 0x0201, 499, /* ȁ Ȁ */
+ 0x0203, 499, /* ȃ Ȃ */
+ 0x0205, 499, /* ȅ Ȅ */
+ 0x0207, 499, /* ȇ Ȇ */
+ 0x0209, 499, /* ȉ Ȉ */
+ 0x020b, 499, /* ȋ Ȋ */
+ 0x020d, 499, /* ȍ Ȍ */
+ 0x020f, 499, /* ȏ Ȏ */
+ 0x0211, 499, /* ȑ Ȑ */
+ 0x0213, 499, /* ȓ Ȓ */
+ 0x0215, 499, /* ȕ Ȕ */
+ 0x0217, 499, /* ȗ Ȗ */
+ 0x0253, 290, /* ɓ Ɓ */
+ 0x0254, 294, /* ɔ Ɔ */
+ 0x025b, 297, /* ɛ Ɛ */
+ 0x0260, 295, /* ɠ Ɠ */
+ 0x0263, 293, /* ɣ Ɣ */
+ 0x0268, 291, /* ɨ Ɨ */
+ 0x0269, 289, /* ɩ Ɩ */
+ 0x026f, 289, /* ɯ Ɯ */
+ 0x0272, 287, /* ɲ Ɲ */
+ 0x0283, 282, /* ʃ Ʃ */
+ 0x0288, 282, /* ʈ Ʈ */
+ 0x0292, 281, /* ʒ Ʒ */
+ 0x03ac, 462, /* ά Ά */
+ 0x03cc, 436, /* ό Ό */
+ 0x03d0, 438, /* ϐ Β */
+ 0x03d1, 443, /* ϑ Θ */
+ 0x03d5, 453, /* ϕ Φ */
+ 0x03d6, 446, /* ϖ Π */
+ 0x03e3, 499, /* ϣ Ϣ */
+ 0x03e5, 499, /* ϥ Ϥ */
+ 0x03e7, 499, /* ϧ Ϧ */
+ 0x03e9, 499, /* ϩ Ϩ */
+ 0x03eb, 499, /* ϫ Ϫ */
+ 0x03ed, 499, /* ϭ Ϭ */
+ 0x03ef, 499, /* ϯ Ϯ */
+ 0x03f0, 414, /* ϰ Κ */
+ 0x03f1, 420, /* ϱ Ρ */
+ 0x0461, 499, /* ѡ Ѡ */
+ 0x0463, 499, /* ѣ Ѣ */
+ 0x0465, 499, /* ѥ Ѥ */
+ 0x0467, 499, /* ѧ Ѧ */
+ 0x0469, 499, /* ѩ Ѩ */
+ 0x046b, 499, /* ѫ Ѫ */
+ 0x046d, 499, /* ѭ Ѭ */
+ 0x046f, 499, /* ѯ Ѯ */
+ 0x0471, 499, /* ѱ Ѱ */
+ 0x0473, 499, /* ѳ Ѳ */
+ 0x0475, 499, /* ѵ Ѵ */
+ 0x0477, 499, /* ѷ Ѷ */
+ 0x0479, 499, /* ѹ Ѹ */
+ 0x047b, 499, /* ѻ Ѻ */
+ 0x047d, 499, /* ѽ Ѽ */
+ 0x047f, 499, /* ѿ Ѿ */
+ 0x0481, 499, /* ҁ Ҁ */
+ 0x0491, 499, /* ґ Ґ */
+ 0x0493, 499, /* ғ Ғ */
+ 0x0495, 499, /* ҕ Ҕ */
+ 0x0497, 499, /* җ Җ */
+ 0x0499, 499, /* ҙ Ҙ */
+ 0x049b, 499, /* қ Қ */
+ 0x049d, 499, /* ҝ Ҝ */
+ 0x049f, 499, /* ҟ Ҟ */
+ 0x04a1, 499, /* ҡ Ҡ */
+ 0x04a3, 499, /* ң Ң */
+ 0x04a5, 499, /* ҥ Ҥ */
+ 0x04a7, 499, /* ҧ Ҧ */
+ 0x04a9, 499, /* ҩ Ҩ */
+ 0x04ab, 499, /* ҫ Ҫ */
+ 0x04ad, 499, /* ҭ Ҭ */
+ 0x04af, 499, /* ү Ү */
+ 0x04b1, 499, /* ұ Ұ */
+ 0x04b3, 499, /* ҳ Ҳ */
+ 0x04b5, 499, /* ҵ Ҵ */
+ 0x04b7, 499, /* ҷ Ҷ */
+ 0x04b9, 499, /* ҹ Ҹ */
+ 0x04bb, 499, /* һ Һ */
+ 0x04bd, 499, /* ҽ Ҽ */
+ 0x04bf, 499, /* ҿ Ҿ */
+ 0x04c2, 499, /* ӂ Ӂ */
+ 0x04c4, 499, /* ӄ Ӄ */
+ 0x04c8, 499, /* ӈ Ӈ */
+ 0x04cc, 499, /* ӌ Ӌ */
+ 0x04d1, 499, /* ӑ Ӑ */
+ 0x04d3, 499, /* ӓ Ӓ */
+ 0x04d5, 499, /* ӕ Ӕ */
+ 0x04d7, 499, /* ӗ Ӗ */
+ 0x04d9, 499, /* ә Ә */
+ 0x04db, 499, /* ӛ Ӛ */
+ 0x04dd, 499, /* ӝ Ӝ */
+ 0x04df, 499, /* ӟ Ӟ */
+ 0x04e1, 499, /* ӡ Ӡ */
+ 0x04e3, 499, /* ӣ Ӣ */
+ 0x04e5, 499, /* ӥ Ӥ */
+ 0x04e7, 499, /* ӧ Ӧ */
+ 0x04e9, 499, /* ө Ө */
+ 0x04eb, 499, /* ӫ Ӫ */
+ 0x04ef, 499, /* ӯ Ӯ */
+ 0x04f1, 499, /* ӱ Ӱ */
+ 0x04f3, 499, /* ӳ Ӳ */
+ 0x04f5, 499, /* ӵ Ӵ */
+ 0x04f9, 499, /* ӹ Ӹ */
+ 0x1e01, 499, /* ḁ Ḁ */
+ 0x1e03, 499, /* ḃ Ḃ */
+ 0x1e05, 499, /* ḅ Ḅ */
+ 0x1e07, 499, /* ḇ Ḇ */
+ 0x1e09, 499, /* ḉ Ḉ */
+ 0x1e0b, 499, /* ḋ Ḋ */
+ 0x1e0d, 499, /* ḍ Ḍ */
+ 0x1e0f, 499, /* ḏ Ḏ */
+ 0x1e11, 499, /* ḑ Ḑ */
+ 0x1e13, 499, /* ḓ Ḓ */
+ 0x1e15, 499, /* ḕ Ḕ */
+ 0x1e17, 499, /* ḗ Ḗ */
+ 0x1e19, 499, /* ḙ Ḙ */
+ 0x1e1b, 499, /* ḛ Ḛ */
+ 0x1e1d, 499, /* ḝ Ḝ */
+ 0x1e1f, 499, /* ḟ Ḟ */
+ 0x1e21, 499, /* ḡ Ḡ */
+ 0x1e23, 499, /* ḣ Ḣ */
+ 0x1e25, 499, /* ḥ Ḥ */
+ 0x1e27, 499, /* ḧ Ḧ */
+ 0x1e29, 499, /* ḩ Ḩ */
+ 0x1e2b, 499, /* ḫ Ḫ */
+ 0x1e2d, 499, /* ḭ Ḭ */
+ 0x1e2f, 499, /* ḯ Ḯ */
+ 0x1e31, 499, /* ḱ Ḱ */
+ 0x1e33, 499, /* ḳ Ḳ */
+ 0x1e35, 499, /* ḵ Ḵ */
+ 0x1e37, 499, /* ḷ Ḷ */
+ 0x1e39, 499, /* ḹ Ḹ */
+ 0x1e3b, 499, /* ḻ Ḻ */
+ 0x1e3d, 499, /* ḽ Ḽ */
+ 0x1e3f, 499, /* ḿ Ḿ */
+ 0x1e41, 499, /* ṁ Ṁ */
+ 0x1e43, 499, /* ṃ Ṃ */
+ 0x1e45, 499, /* ṅ Ṅ */
+ 0x1e47, 499, /* ṇ Ṇ */
+ 0x1e49, 499, /* ṉ Ṉ */
+ 0x1e4b, 499, /* ṋ Ṋ */
+ 0x1e4d, 499, /* ṍ Ṍ */
+ 0x1e4f, 499, /* ṏ Ṏ */
+ 0x1e51, 499, /* ṑ Ṑ */
+ 0x1e53, 499, /* ṓ Ṓ */
+ 0x1e55, 499, /* ṕ Ṕ */
+ 0x1e57, 499, /* ṗ Ṗ */
+ 0x1e59, 499, /* ṙ Ṙ */
+ 0x1e5b, 499, /* ṛ Ṛ */
+ 0x1e5d, 499, /* ṝ Ṝ */
+ 0x1e5f, 499, /* ṟ Ṟ */
+ 0x1e61, 499, /* ṡ Ṡ */
+ 0x1e63, 499, /* ṣ Ṣ */
+ 0x1e65, 499, /* ṥ Ṥ */
+ 0x1e67, 499, /* ṧ Ṧ */
+ 0x1e69, 499, /* ṩ Ṩ */
+ 0x1e6b, 499, /* ṫ Ṫ */
+ 0x1e6d, 499, /* ṭ Ṭ */
+ 0x1e6f, 499, /* ṯ Ṯ */
+ 0x1e71, 499, /* ṱ Ṱ */
+ 0x1e73, 499, /* ṳ Ṳ */
+ 0x1e75, 499, /* ṵ Ṵ */
+ 0x1e77, 499, /* ṷ Ṷ */
+ 0x1e79, 499, /* ṹ Ṹ */
+ 0x1e7b, 499, /* ṻ Ṻ */
+ 0x1e7d, 499, /* ṽ Ṽ */
+ 0x1e7f, 499, /* ṿ Ṿ */
+ 0x1e81, 499, /* ẁ Ẁ */
+ 0x1e83, 499, /* ẃ Ẃ */
+ 0x1e85, 499, /* ẅ Ẅ */
+ 0x1e87, 499, /* ẇ Ẇ */
+ 0x1e89, 499, /* ẉ Ẉ */
+ 0x1e8b, 499, /* ẋ Ẋ */
+ 0x1e8d, 499, /* ẍ Ẍ */
+ 0x1e8f, 499, /* ẏ Ẏ */
+ 0x1e91, 499, /* ẑ Ẑ */
+ 0x1e93, 499, /* ẓ Ẓ */
+ 0x1e95, 499, /* ẕ Ẕ */
+ 0x1ea1, 499, /* ạ Ạ */
+ 0x1ea3, 499, /* ả Ả */
+ 0x1ea5, 499, /* ấ Ấ */
+ 0x1ea7, 499, /* ầ Ầ */
+ 0x1ea9, 499, /* ẩ Ẩ */
+ 0x1eab, 499, /* ẫ Ẫ */
+ 0x1ead, 499, /* ậ Ậ */
+ 0x1eaf, 499, /* ắ Ắ */
+ 0x1eb1, 499, /* ằ Ằ */
+ 0x1eb3, 499, /* ẳ Ẳ */
+ 0x1eb5, 499, /* ẵ Ẵ */
+ 0x1eb7, 499, /* ặ Ặ */
+ 0x1eb9, 499, /* ẹ Ẹ */
+ 0x1ebb, 499, /* ẻ Ẻ */
+ 0x1ebd, 499, /* ẽ Ẽ */
+ 0x1ebf, 499, /* ế Ế */
+ 0x1ec1, 499, /* ề Ề */
+ 0x1ec3, 499, /* ể Ể */
+ 0x1ec5, 499, /* ễ Ễ */
+ 0x1ec7, 499, /* ệ Ệ */
+ 0x1ec9, 499, /* ỉ Ỉ */
+ 0x1ecb, 499, /* ị Ị */
+ 0x1ecd, 499, /* ọ Ọ */
+ 0x1ecf, 499, /* ỏ Ỏ */
+ 0x1ed1, 499, /* ố Ố */
+ 0x1ed3, 499, /* ồ Ồ */
+ 0x1ed5, 499, /* ổ Ổ */
+ 0x1ed7, 499, /* ỗ Ỗ */
+ 0x1ed9, 499, /* ộ Ộ */
+ 0x1edb, 499, /* ớ Ớ */
+ 0x1edd, 499, /* ờ Ờ */
+ 0x1edf, 499, /* ở Ở */
+ 0x1ee1, 499, /* ỡ Ỡ */
+ 0x1ee3, 499, /* ợ Ợ */
+ 0x1ee5, 499, /* ụ Ụ */
+ 0x1ee7, 499, /* ủ Ủ */
+ 0x1ee9, 499, /* ứ Ứ */
+ 0x1eeb, 499, /* ừ Ừ */
+ 0x1eed, 499, /* ử Ử */
+ 0x1eef, 499, /* ữ Ữ */
+ 0x1ef1, 499, /* ự Ự */
+ 0x1ef3, 499, /* ỳ Ỳ */
+ 0x1ef5, 499, /* ỵ Ỵ */
+ 0x1ef7, 499, /* ỷ Ỷ */
+ 0x1ef9, 499, /* ỹ Ỹ */
+ 0x1f51, 508, /* ὑ Ὑ */
+ 0x1f53, 508, /* ὓ Ὓ */
+ 0x1f55, 508, /* ὕ Ὕ */
+ 0x1f57, 508, /* ὗ Ὗ */
+ 0x1fb3, 509, /* ᾳ ᾼ */
+ 0x1fc3, 509, /* ῃ ῌ */
+ 0x1fe5, 507, /* ῥ Ῥ */
+ 0x1ff3, 509, /* ῳ ῼ */
+};
+
+/*
+ * upper case ranges
+ * 3rd col is conversion excess 500
+ */
+static
+Rune __tolower2[] =
+{
+ 0x0041, 0x005a, 532, /* A-Z a-z */
+ 0x00c0, 0x00d6, 532, /* À-Ö à-ö */
+ 0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */
+ 0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */
+ 0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */
+ 0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */
+ 0x0388, 0x038a, 537, /* Έ-Ί έ-ί */
+ 0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */
+ 0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */
+ 0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */
+ 0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */
+ 0x040e, 0x040f, 580, /* Ў-Џ ў-џ */
+ 0x0410, 0x042f, 532, /* А-Я а-я */
+ 0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */
+ 0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */
+ 0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */
+ 0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */
+ 0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */
+ 0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */
+ 0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */
+ 0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */
+ 0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */
+ 0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */
+ 0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */
+ 0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */
+ 0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */
+ 0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */
+ 0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */
+ 0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */
+ 0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */
+ 0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */
+ 0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */
+ 0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */
+ 0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */
+ 0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */
+ 0xff21, 0xff3a, 532, /* A-Z a-z */
+};
+
+/*
+ * upper case singlets
+ * 2nd col is conversion excess 500
+ */
+static
+Rune __tolower1[] =
+{
+ 0x0100, 501, /* Ā ā */
+ 0x0102, 501, /* Ă ă */
+ 0x0104, 501, /* Ą ą */
+ 0x0106, 501, /* Ć ć */
+ 0x0108, 501, /* Ĉ ĉ */
+ 0x010a, 501, /* Ċ ċ */
+ 0x010c, 501, /* Č č */
+ 0x010e, 501, /* Ď ď */
+ 0x0110, 501, /* Đ đ */
+ 0x0112, 501, /* Ē ē */
+ 0x0114, 501, /* Ĕ ĕ */
+ 0x0116, 501, /* Ė ė */
+ 0x0118, 501, /* Ę ę */
+ 0x011a, 501, /* Ě ě */
+ 0x011c, 501, /* Ĝ ĝ */
+ 0x011e, 501, /* Ğ ğ */
+ 0x0120, 501, /* Ġ ġ */
+ 0x0122, 501, /* Ģ ģ */
+ 0x0124, 501, /* Ĥ ĥ */
+ 0x0126, 501, /* Ħ ħ */
+ 0x0128, 501, /* Ĩ ĩ */
+ 0x012a, 501, /* Ī ī */
+ 0x012c, 501, /* Ĭ ĭ */
+ 0x012e, 501, /* Į į */
+ 0x0130, 301, /* İ i */
+ 0x0132, 501, /* IJ ij */
+ 0x0134, 501, /* Ĵ ĵ */
+ 0x0136, 501, /* Ķ ķ */
+ 0x0139, 501, /* Ĺ ĺ */
+ 0x013b, 501, /* Ļ ļ */
+ 0x013d, 501, /* Ľ ľ */
+ 0x013f, 501, /* Ŀ ŀ */
+ 0x0141, 501, /* Ł ł */
+ 0x0143, 501, /* Ń ń */
+ 0x0145, 501, /* Ņ ņ */
+ 0x0147, 501, /* Ň ň */
+ 0x014a, 501, /* Ŋ ŋ */
+ 0x014c, 501, /* Ō ō */
+ 0x014e, 501, /* Ŏ ŏ */
+ 0x0150, 501, /* Ő ő */
+ 0x0152, 501, /* Œ œ */
+ 0x0154, 501, /* Ŕ ŕ */
+ 0x0156, 501, /* Ŗ ŗ */
+ 0x0158, 501, /* Ř ř */
+ 0x015a, 501, /* Ś ś */
+ 0x015c, 501, /* Ŝ ŝ */
+ 0x015e, 501, /* Ş ş */
+ 0x0160, 501, /* Š š */
+ 0x0162, 501, /* Ţ ţ */
+ 0x0164, 501, /* Ť ť */
+ 0x0166, 501, /* Ŧ ŧ */
+ 0x0168, 501, /* Ũ ũ */
+ 0x016a, 501, /* Ū ū */
+ 0x016c, 501, /* Ŭ ŭ */
+ 0x016e, 501, /* Ů ů */
+ 0x0170, 501, /* Ű ű */
+ 0x0172, 501, /* Ų ų */
+ 0x0174, 501, /* Ŵ ŵ */
+ 0x0176, 501, /* Ŷ ŷ */
+ 0x0178, 379, /* Ÿ ÿ */
+ 0x0179, 501, /* Ź ź */
+ 0x017b, 501, /* Ż ż */
+ 0x017d, 501, /* Ž ž */
+ 0x0181, 710, /* Ɓ ɓ */
+ 0x0182, 501, /* Ƃ ƃ */
+ 0x0184, 501, /* Ƅ ƅ */
+ 0x0186, 706, /* Ɔ ɔ */
+ 0x0187, 501, /* Ƈ ƈ */
+ 0x018b, 501, /* Ƌ ƌ */
+ 0x0190, 703, /* Ɛ ɛ */
+ 0x0191, 501, /* Ƒ ƒ */
+ 0x0193, 705, /* Ɠ ɠ */
+ 0x0194, 707, /* Ɣ ɣ */
+ 0x0196, 711, /* Ɩ ɩ */
+ 0x0197, 709, /* Ɨ ɨ */
+ 0x0198, 501, /* Ƙ ƙ */
+ 0x019c, 711, /* Ɯ ɯ */
+ 0x019d, 713, /* Ɲ ɲ */
+ 0x01a0, 501, /* Ơ ơ */
+ 0x01a2, 501, /* Ƣ ƣ */
+ 0x01a4, 501, /* Ƥ ƥ */
+ 0x01a7, 501, /* Ƨ ƨ */
+ 0x01a9, 718, /* Ʃ ʃ */
+ 0x01ac, 501, /* Ƭ ƭ */
+ 0x01ae, 718, /* Ʈ ʈ */
+ 0x01af, 501, /* Ư ư */
+ 0x01b3, 501, /* Ƴ ƴ */
+ 0x01b5, 501, /* Ƶ ƶ */
+ 0x01b7, 719, /* Ʒ ʒ */
+ 0x01b8, 501, /* Ƹ ƹ */
+ 0x01bc, 501, /* Ƽ ƽ */
+ 0x01c4, 502, /* DŽ dž */
+ 0x01c5, 501, /* Dž dž */
+ 0x01c7, 502, /* LJ lj */
+ 0x01c8, 501, /* Lj lj */
+ 0x01ca, 502, /* NJ nj */
+ 0x01cb, 501, /* Nj nj */
+ 0x01cd, 501, /* Ǎ ǎ */
+ 0x01cf, 501, /* Ǐ ǐ */
+ 0x01d1, 501, /* Ǒ ǒ */
+ 0x01d3, 501, /* Ǔ ǔ */
+ 0x01d5, 501, /* Ǖ ǖ */
+ 0x01d7, 501, /* Ǘ ǘ */
+ 0x01d9, 501, /* Ǚ ǚ */
+ 0x01db, 501, /* Ǜ ǜ */
+ 0x01de, 501, /* Ǟ ǟ */
+ 0x01e0, 501, /* Ǡ ǡ */
+ 0x01e2, 501, /* Ǣ ǣ */
+ 0x01e4, 501, /* Ǥ ǥ */
+ 0x01e6, 501, /* Ǧ ǧ */
+ 0x01e8, 501, /* Ǩ ǩ */
+ 0x01ea, 501, /* Ǫ ǫ */
+ 0x01ec, 501, /* Ǭ ǭ */
+ 0x01ee, 501, /* Ǯ ǯ */
+ 0x01f1, 502, /* DZ dz */
+ 0x01f2, 501, /* Dz dz */
+ 0x01f4, 501, /* Ǵ ǵ */
+ 0x01fa, 501, /* Ǻ ǻ */
+ 0x01fc, 501, /* Ǽ ǽ */
+ 0x01fe, 501, /* Ǿ ǿ */
+ 0x0200, 501, /* Ȁ ȁ */
+ 0x0202, 501, /* Ȃ ȃ */
+ 0x0204, 501, /* Ȅ ȅ */
+ 0x0206, 501, /* Ȇ ȇ */
+ 0x0208, 501, /* Ȉ ȉ */
+ 0x020a, 501, /* Ȋ ȋ */
+ 0x020c, 501, /* Ȍ ȍ */
+ 0x020e, 501, /* Ȏ ȏ */
+ 0x0210, 501, /* Ȑ ȑ */
+ 0x0212, 501, /* Ȓ ȓ */
+ 0x0214, 501, /* Ȕ ȕ */
+ 0x0216, 501, /* Ȗ ȗ */
+ 0x0386, 538, /* Ά ά */
+ 0x038c, 564, /* Ό ό */
+ 0x03e2, 501, /* Ϣ ϣ */
+ 0x03e4, 501, /* Ϥ ϥ */
+ 0x03e6, 501, /* Ϧ ϧ */
+ 0x03e8, 501, /* Ϩ ϩ */
+ 0x03ea, 501, /* Ϫ ϫ */
+ 0x03ec, 501, /* Ϭ ϭ */
+ 0x03ee, 501, /* Ϯ ϯ */
+ 0x0460, 501, /* Ѡ ѡ */
+ 0x0462, 501, /* Ѣ ѣ */
+ 0x0464, 501, /* Ѥ ѥ */
+ 0x0466, 501, /* Ѧ ѧ */
+ 0x0468, 501, /* Ѩ ѩ */
+ 0x046a, 501, /* Ѫ ѫ */
+ 0x046c, 501, /* Ѭ ѭ */
+ 0x046e, 501, /* Ѯ ѯ */
+ 0x0470, 501, /* Ѱ ѱ */
+ 0x0472, 501, /* Ѳ ѳ */
+ 0x0474, 501, /* Ѵ ѵ */
+ 0x0476, 501, /* Ѷ ѷ */
+ 0x0478, 501, /* Ѹ ѹ */
+ 0x047a, 501, /* Ѻ ѻ */
+ 0x047c, 501, /* Ѽ ѽ */
+ 0x047e, 501, /* Ѿ ѿ */
+ 0x0480, 501, /* Ҁ ҁ */
+ 0x0490, 501, /* Ґ ґ */
+ 0x0492, 501, /* Ғ ғ */
+ 0x0494, 501, /* Ҕ ҕ */
+ 0x0496, 501, /* Җ җ */
+ 0x0498, 501, /* Ҙ ҙ */
+ 0x049a, 501, /* Қ қ */
+ 0x049c, 501, /* Ҝ ҝ */
+ 0x049e, 501, /* Ҟ ҟ */
+ 0x04a0, 501, /* Ҡ ҡ */
+ 0x04a2, 501, /* Ң ң */
+ 0x04a4, 501, /* Ҥ ҥ */
+ 0x04a6, 501, /* Ҧ ҧ */
+ 0x04a8, 501, /* Ҩ ҩ */
+ 0x04aa, 501, /* Ҫ ҫ */
+ 0x04ac, 501, /* Ҭ ҭ */
+ 0x04ae, 501, /* Ү ү */
+ 0x04b0, 501, /* Ұ ұ */
+ 0x04b2, 501, /* Ҳ ҳ */
+ 0x04b4, 501, /* Ҵ ҵ */
+ 0x04b6, 501, /* Ҷ ҷ */
+ 0x04b8, 501, /* Ҹ ҹ */
+ 0x04ba, 501, /* Һ һ */
+ 0x04bc, 501, /* Ҽ ҽ */
+ 0x04be, 501, /* Ҿ ҿ */
+ 0x04c1, 501, /* Ӂ ӂ */
+ 0x04c3, 501, /* Ӄ ӄ */
+ 0x04c7, 501, /* Ӈ ӈ */
+ 0x04cb, 501, /* Ӌ ӌ */
+ 0x04d0, 501, /* Ӑ ӑ */
+ 0x04d2, 501, /* Ӓ ӓ */
+ 0x04d4, 501, /* Ӕ ӕ */
+ 0x04d6, 501, /* Ӗ ӗ */
+ 0x04d8, 501, /* Ә ә */
+ 0x04da, 501, /* Ӛ ӛ */
+ 0x04dc, 501, /* Ӝ ӝ */
+ 0x04de, 501, /* Ӟ ӟ */
+ 0x04e0, 501, /* Ӡ ӡ */
+ 0x04e2, 501, /* Ӣ ӣ */
+ 0x04e4, 501, /* Ӥ ӥ */
+ 0x04e6, 501, /* Ӧ ӧ */
+ 0x04e8, 501, /* Ө ө */
+ 0x04ea, 501, /* Ӫ ӫ */
+ 0x04ee, 501, /* Ӯ ӯ */
+ 0x04f0, 501, /* Ӱ ӱ */
+ 0x04f2, 501, /* Ӳ ӳ */
+ 0x04f4, 501, /* Ӵ ӵ */
+ 0x04f8, 501, /* Ӹ ӹ */
+ 0x1e00, 501, /* Ḁ ḁ */
+ 0x1e02, 501, /* Ḃ ḃ */
+ 0x1e04, 501, /* Ḅ ḅ */
+ 0x1e06, 501, /* Ḇ ḇ */
+ 0x1e08, 501, /* Ḉ ḉ */
+ 0x1e0a, 501, /* Ḋ ḋ */
+ 0x1e0c, 501, /* Ḍ ḍ */
+ 0x1e0e, 501, /* Ḏ ḏ */
+ 0x1e10, 501, /* Ḑ ḑ */
+ 0x1e12, 501, /* Ḓ ḓ */
+ 0x1e14, 501, /* Ḕ ḕ */
+ 0x1e16, 501, /* Ḗ ḗ */
+ 0x1e18, 501, /* Ḙ ḙ */
+ 0x1e1a, 501, /* Ḛ ḛ */
+ 0x1e1c, 501, /* Ḝ ḝ */
+ 0x1e1e, 501, /* Ḟ ḟ */
+ 0x1e20, 501, /* Ḡ ḡ */
+ 0x1e22, 501, /* Ḣ ḣ */
+ 0x1e24, 501, /* Ḥ ḥ */
+ 0x1e26, 501, /* Ḧ ḧ */
+ 0x1e28, 501, /* Ḩ ḩ */
+ 0x1e2a, 501, /* Ḫ ḫ */
+ 0x1e2c, 501, /* Ḭ ḭ */
+ 0x1e2e, 501, /* Ḯ ḯ */
+ 0x1e30, 501, /* Ḱ ḱ */
+ 0x1e32, 501, /* Ḳ ḳ */
+ 0x1e34, 501, /* Ḵ ḵ */
+ 0x1e36, 501, /* Ḷ ḷ */
+ 0x1e38, 501, /* Ḹ ḹ */
+ 0x1e3a, 501, /* Ḻ ḻ */
+ 0x1e3c, 501, /* Ḽ ḽ */
+ 0x1e3e, 501, /* Ḿ ḿ */
+ 0x1e40, 501, /* Ṁ ṁ */
+ 0x1e42, 501, /* Ṃ ṃ */
+ 0x1e44, 501, /* Ṅ ṅ */
+ 0x1e46, 501, /* Ṇ ṇ */
+ 0x1e48, 501, /* Ṉ ṉ */
+ 0x1e4a, 501, /* Ṋ ṋ */
+ 0x1e4c, 501, /* Ṍ ṍ */
+ 0x1e4e, 501, /* Ṏ ṏ */
+ 0x1e50, 501, /* Ṑ ṑ */
+ 0x1e52, 501, /* Ṓ ṓ */
+ 0x1e54, 501, /* Ṕ ṕ */
+ 0x1e56, 501, /* Ṗ ṗ */
+ 0x1e58, 501, /* Ṙ ṙ */
+ 0x1e5a, 501, /* Ṛ ṛ */
+ 0x1e5c, 501, /* Ṝ ṝ */
+ 0x1e5e, 501, /* Ṟ ṟ */
+ 0x1e60, 501, /* Ṡ ṡ */
+ 0x1e62, 501, /* Ṣ ṣ */
+ 0x1e64, 501, /* Ṥ ṥ */
+ 0x1e66, 501, /* Ṧ ṧ */
+ 0x1e68, 501, /* Ṩ ṩ */
+ 0x1e6a, 501, /* Ṫ ṫ */
+ 0x1e6c, 501, /* Ṭ ṭ */
+ 0x1e6e, 501, /* Ṯ ṯ */
+ 0x1e70, 501, /* Ṱ ṱ */
+ 0x1e72, 501, /* Ṳ ṳ */
+ 0x1e74, 501, /* Ṵ ṵ */
+ 0x1e76, 501, /* Ṷ ṷ */
+ 0x1e78, 501, /* Ṹ ṹ */
+ 0x1e7a, 501, /* Ṻ ṻ */
+ 0x1e7c, 501, /* Ṽ ṽ */
+ 0x1e7e, 501, /* Ṿ ṿ */
+ 0x1e80, 501, /* Ẁ ẁ */
+ 0x1e82, 501, /* Ẃ ẃ */
+ 0x1e84, 501, /* Ẅ ẅ */
+ 0x1e86, 501, /* Ẇ ẇ */
+ 0x1e88, 501, /* Ẉ ẉ */
+ 0x1e8a, 501, /* Ẋ ẋ */
+ 0x1e8c, 501, /* Ẍ ẍ */
+ 0x1e8e, 501, /* Ẏ ẏ */
+ 0x1e90, 501, /* Ẑ ẑ */
+ 0x1e92, 501, /* Ẓ ẓ */
+ 0x1e94, 501, /* Ẕ ẕ */
+ 0x1ea0, 501, /* Ạ ạ */
+ 0x1ea2, 501, /* Ả ả */
+ 0x1ea4, 501, /* Ấ ấ */
+ 0x1ea6, 501, /* Ầ ầ */
+ 0x1ea8, 501, /* Ẩ ẩ */
+ 0x1eaa, 501, /* Ẫ ẫ */
+ 0x1eac, 501, /* Ậ ậ */
+ 0x1eae, 501, /* Ắ ắ */
+ 0x1eb0, 501, /* Ằ ằ */
+ 0x1eb2, 501, /* Ẳ ẳ */
+ 0x1eb4, 501, /* Ẵ ẵ */
+ 0x1eb6, 501, /* Ặ ặ */
+ 0x1eb8, 501, /* Ẹ ẹ */
+ 0x1eba, 501, /* Ẻ ẻ */
+ 0x1ebc, 501, /* Ẽ ẽ */
+ 0x1ebe, 501, /* Ế ế */
+ 0x1ec0, 501, /* Ề ề */
+ 0x1ec2, 501, /* Ể ể */
+ 0x1ec4, 501, /* Ễ ễ */
+ 0x1ec6, 501, /* Ệ ệ */
+ 0x1ec8, 501, /* Ỉ ỉ */
+ 0x1eca, 501, /* Ị ị */
+ 0x1ecc, 501, /* Ọ ọ */
+ 0x1ece, 501, /* Ỏ ỏ */
+ 0x1ed0, 501, /* Ố ố */
+ 0x1ed2, 501, /* Ồ ồ */
+ 0x1ed4, 501, /* Ổ ổ */
+ 0x1ed6, 501, /* Ỗ ỗ */
+ 0x1ed8, 501, /* Ộ ộ */
+ 0x1eda, 501, /* Ớ ớ */
+ 0x1edc, 501, /* Ờ ờ */
+ 0x1ede, 501, /* Ở ở */
+ 0x1ee0, 501, /* Ỡ ỡ */
+ 0x1ee2, 501, /* Ợ ợ */
+ 0x1ee4, 501, /* Ụ ụ */
+ 0x1ee6, 501, /* Ủ ủ */
+ 0x1ee8, 501, /* Ứ ứ */
+ 0x1eea, 501, /* Ừ ừ */
+ 0x1eec, 501, /* Ử ử */
+ 0x1eee, 501, /* Ữ ữ */
+ 0x1ef0, 501, /* Ự ự */
+ 0x1ef2, 501, /* Ỳ ỳ */
+ 0x1ef4, 501, /* Ỵ ỵ */
+ 0x1ef6, 501, /* Ỷ ỷ */
+ 0x1ef8, 501, /* Ỹ ỹ */
+ 0x1f59, 492, /* Ὑ ὑ */
+ 0x1f5b, 492, /* Ὓ ὓ */
+ 0x1f5d, 492, /* Ὕ ὕ */
+ 0x1f5f, 492, /* Ὗ ὗ */
+ 0x1fbc, 491, /* ᾼ ᾳ */
+ 0x1fcc, 491, /* ῌ ῃ */
+ 0x1fec, 493, /* Ῥ ῥ */
+ 0x1ffc, 491, /* ῼ ῳ */
+};
+
+/*
+ * title characters are those between
+ * upper and lower case. ie DZ Dz dz
+ */
+static
+Rune __totitle1[] =
+{
+ 0x01c4, 501, /* DŽ Dž */
+ 0x01c6, 499, /* dž Dž */
+ 0x01c7, 501, /* LJ Lj */
+ 0x01c9, 499, /* lj Lj */
+ 0x01ca, 501, /* NJ Nj */
+ 0x01cc, 499, /* nj Nj */
+ 0x01f1, 501, /* DZ Dz */
+ 0x01f3, 499, /* dz Dz */
+};
+
+static Rune*
+bsearch(Rune c, Rune *t, int n, int ne)
+{
+ Rune *p;
+ int m;
+
+ while(n > 1) {
+ m = n/2;
+ p = t + m*ne;
+ if(c >= p[0]) {
+ t = p;
+ n = n-m;
+ } else
+ n = m;
+ }
+ if(n && c >= t[0])
+ return t;
+ return 0;
+}
+
+Rune
+tolowerrune(Rune c)
+{
+ Rune *p;
+
+ p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 500;
+ p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 500;
+ return c;
+}
+
+Rune
+toupperrune(Rune c)
+{
+ Rune *p;
+
+ p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 500;
+ p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 500;
+ return c;
+}
+
+Rune
+totitlerune(Rune c)
+{
+ Rune *p;
+
+ p = bsearch(c, __totitle1, nelem(__totitle1)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 500;
+ return c;
+}
+
+int
+islowerrune(Rune c)
+{
+ Rune *p;
+
+ p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+int
+isupperrune(Rune c)
+{
+ Rune *p;
+
+ p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+int
+isalpharune(Rune c)
+{
+ Rune *p;
+
+ if(isupperrune(c) || islowerrune(c))
+ return 1;
+ p = bsearch(c, __alpha2, nelem(__alpha2)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = bsearch(c, __alpha1, nelem(__alpha1), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+int
+istitlerune(Rune c)
+{
+ return isupperrune(c) && islowerrune(c);
+}
+
+int
+isspacerune(Rune c)
+{
+ Rune *p;
+
+ p = bsearch(c, __space2, nelem(__space2)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ return 0;
+}
diff --git a/src/lib9/utf/utfdef.h b/src/lib9/utf/utfdef.h
new file mode 100644
index 000000000..ba3749a9c
--- /dev/null
+++ b/src/lib9/utf/utfdef.h
@@ -0,0 +1,47 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * compiler directive on Plan 9
+ */
+#ifndef USED
+#define USED(x) if(x);else
+#endif
+
+/*
+ * easiest way to make sure these are defined
+ */
+#define uchar _fmtuchar
+#define ushort _fmtushort
+#define uint _fmtuint
+#define ulong _fmtulong
+#define vlong _fmtvlong
+#define uvlong _fmtuvlong
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef unsigned long long uvlong;
+typedef long long vlong;
+
+/*
+ * nil cannot be ((void*)0) on ANSI C,
+ * because it is used for function pointers
+ */
+#undef nil
+#define nil 0
+
+#undef nelem
+#define nelem ((void*)0)
+
diff --git a/src/lib9/utf/utfecpy.c b/src/lib9/utf/utfecpy.c
new file mode 100644
index 000000000..cf3535fb4
--- /dev/null
+++ b/src/lib9/utf/utfecpy.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#define _BSD_SOURCE 1 /* memccpy */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+char*
+utfecpy(char *to, char *e, char *from)
+{
+ char *end;
+
+ if(to >= e)
+ return to;
+ end = memccpy(to, from, '\0', e - to);
+ if(end == nil){
+ end = e-1;
+ while(end>to && (*--end&0xC0)==0x80)
+ ;
+ *end = '\0';
+ }else{
+ end--;
+ }
+ return end;
+}
diff --git a/src/lib9/utf/utflen.c b/src/lib9/utf/utflen.c
new file mode 100644
index 000000000..769805a5a
--- /dev/null
+++ b/src/lib9/utf/utflen.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+int
+utflen(char *s)
+{
+ int c;
+ long n;
+ Rune rune;
+
+ n = 0;
+ for(;;) {
+ c = *(uchar*)s;
+ if(c < Runeself) {
+ if(c == 0)
+ return n;
+ s++;
+ } else
+ s += chartorune(&rune, s);
+ n++;
+ }
+}
diff --git a/src/lib9/utf/utfnlen.c b/src/lib9/utf/utfnlen.c
new file mode 100644
index 000000000..668032995
--- /dev/null
+++ b/src/lib9/utf/utfnlen.c
@@ -0,0 +1,41 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+int
+utfnlen(char *s, long m)
+{
+ int c;
+ long n;
+ Rune rune;
+ char *es;
+
+ es = s + m;
+ for(n = 0; s < es; n++) {
+ c = *(uchar*)s;
+ if(c < Runeself){
+ if(c == '\0')
+ break;
+ s++;
+ continue;
+ }
+ if(!fullrune(s, es-s))
+ break;
+ s += chartorune(&rune, s);
+ }
+ return n;
+}
diff --git a/src/lib9/utf/utfrrune.c b/src/lib9/utf/utfrrune.c
new file mode 100644
index 000000000..cff12b5e2
--- /dev/null
+++ b/src/lib9/utf/utfrrune.c
@@ -0,0 +1,45 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+char*
+utfrrune(char *s, long c)
+{
+ long c1;
+ Rune r;
+ char *s1;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strrchr(s, c);
+
+ s1 = 0;
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return s1;
+ if(c1 == c)
+ s1 = s;
+ s++;
+ continue;
+ }
+ c1 = chartorune(&r, s);
+ if(r == c)
+ s1 = s;
+ s += c1;
+ }
+}
diff --git a/src/lib9/utf/utfrune.c b/src/lib9/utf/utfrune.c
new file mode 100644
index 000000000..52b83599e
--- /dev/null
+++ b/src/lib9/utf/utfrune.c
@@ -0,0 +1,44 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+char*
+utfrune(char *s, long c)
+{
+ long c1;
+ Rune r;
+ int n;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strchr(s, c);
+
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return 0;
+ if(c1 == c)
+ return s;
+ s++;
+ continue;
+ }
+ n = chartorune(&r, s);
+ if(r == c)
+ return s;
+ s += n;
+ }
+}
diff --git a/src/lib9/utf/utfutf.c b/src/lib9/utf/utfutf.c
new file mode 100644
index 000000000..13c850208
--- /dev/null
+++ b/src/lib9/utf/utfutf.c
@@ -0,0 +1,41 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "utf.h"
+
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+utfutf(char *s1, char *s2)
+{
+ char *p;
+ long f, n1, n2;
+ Rune r;
+
+ n1 = chartorune(&r, s2);
+ f = r;
+ if(f <= Runesync) /* represents self */
+ return strstr(s1, s2);
+
+ n2 = strlen(s2);
+ for(p=s1; p=utfrune(p, f); p+=n1)
+ if(strncmp(p, s2, n2) == 0)
+ return p;
+ return 0;
+}