tMove utf, fmt.  Small header file changes. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 91c13e54b5d631b65e2f8344d5e0abd058f78ba1
 (DIR) parent 5a8e63b2f016735364d17866d5e2bcb35d20c78b
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sun, 29 Feb 2004 22:11:15 +0000
       
       Move utf, fmt.  Small header file changes.
       
       Diffstat:
         M include/complete.h                  |       5 ++++-
         M include/lib9.h                      |       2 ++
         M include/plumb.h                     |       1 +
         M include/thread.h                    |      14 ++++++++++++--
         A src/lib9/fmt/LICENSE                |      19 +++++++++++++++++++
         A src/lib9/fmt/NOTICE                 |      19 +++++++++++++++++++
         A src/lib9/fmt/README                 |      19 +++++++++++++++++++
         A src/lib9/fmt/charstod.c             |      85 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/dofmt.c                |     558 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/dorfmt.c               |      61 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/errfmt.c               |      28 ++++++++++++++++++++++++++++
         A src/lib9/fmt/fltfmt.c               |     610 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmt.c                  |     221 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtdef.h               |     121 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtfd.c                |      46 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtfdflush.c           |      33 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtlock.c              |      28 ++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtprint.c             |      47 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtquote.c             |     262 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtrune.c              |      40 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtstr.c               |      65 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fmtvprint.c            |      46 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/fprint.c               |      28 ++++++++++++++++++++++++++++
         A src/lib9/fmt/mkfile                 |      57 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/nan.h                  |       4 ++++
         A src/lib9/fmt/nan64.c                |      76 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/pow10.c                |      57 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/print.c                |      28 ++++++++++++++++++++++++++++
         A src/lib9/fmt/runefmtstr.c           |      65 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/runeseprint.c          |      30 ++++++++++++++++++++++++++++++
         A src/lib9/fmt/runesmprint.c          |      30 ++++++++++++++++++++++++++++++
         A src/lib9/fmt/runesnprint.c          |      31 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/runesprint.c           |      30 ++++++++++++++++++++++++++++++
         A src/lib9/fmt/runevseprint.c         |      39 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/runevsmprint.c         |      37 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/runevsnprint.c         |      38 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/seprint.c              |      27 +++++++++++++++++++++++++++
         A src/lib9/fmt/smprint.c              |      27 +++++++++++++++++++++++++++
         A src/lib9/fmt/snprint.c              |      28 ++++++++++++++++++++++++++++
         A src/lib9/fmt/sprint.c               |      27 +++++++++++++++++++++++++++
         A src/lib9/fmt/strtod.c               |     539 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/strtod.h               |       4 ++++
         A src/lib9/fmt/test.c                 |      39 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/vfprint.c              |      31 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/vseprint.c             |      37 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/vsmprint.c             |      36 +++++++++++++++++++++++++++++++
         A src/lib9/fmt/vsnprint.c             |      37 +++++++++++++++++++++++++++++++
         A src/lib9/utf/LICENSE                |      13 +++++++++++++
         A src/lib9/utf/NOTICE                 |      13 +++++++++++++
         A src/lib9/utf/README                 |      13 +++++++++++++
         A src/lib9/utf/lib9.h                 |      17 +++++++++++++++++
         A src/lib9/utf/mkfile                 |      31 +++++++++++++++++++++++++++++++
         A src/lib9/utf/rune.c                 |     177 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrcat.c           |      25 +++++++++++++++++++++++++
         A src/lib9/utf/runestrchr.c           |      35 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrcmp.c           |      35 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrcpy.c           |      28 ++++++++++++++++++++++++++++
         A src/lib9/utf/runestrdup.c           |      30 ++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrecpy.c          |      32 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrlen.c           |      24 ++++++++++++++++++++++++
         A src/lib9/utf/runestrncat.c          |      32 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrncmp.c          |      37 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrncpy.c          |      33 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrrchr.c          |      30 ++++++++++++++++++++++++++++++
         A src/lib9/utf/runestrstr.c           |      44 +++++++++++++++++++++++++++++++
         A src/lib9/utf/runetype.c             |    1152 +++++++++++++++++++++++++++++++
         A src/lib9/utf/utfdef.h               |      14 ++++++++++++++
         A src/lib9/utf/utfecpy.c              |      36 +++++++++++++++++++++++++++++++
         A src/lib9/utf/utflen.c               |      38 +++++++++++++++++++++++++++++++
         A src/lib9/utf/utfnlen.c              |      41 +++++++++++++++++++++++++++++++
         A src/lib9/utf/utfrrune.c             |      46 +++++++++++++++++++++++++++++++
         A src/lib9/utf/utfrune.c              |      45 +++++++++++++++++++++++++++++++
         A src/lib9/utf/utfutf.c               |      41 +++++++++++++++++++++++++++++++
       
       73 files changed, 5771 insertions(+), 3 deletions(-)
       ---
 (DIR) diff --git a/include/complete.h b/include/complete.h
       t@@ -1,5 +1,7 @@
       +/*
        #pragma        lib        "libcomplete.a"
        #pragma src "/sys/src/libcomplete"
       +*/
        
        typedef struct Completion Completion;
        
       t@@ -7,7 +9,8 @@ struct Completion{
                uchar advance;                /* whether forward progress has been made */
                uchar complete;        /* whether the completion now represents a file or directory */
                char *string;                /* the string to advance, suffixed " " or "/" for file or directory */
       -        int nfile;                        /* number of files that matched */
       +        int nmatch;                /* number of files that matched */
       +        int nfile;                        /* number of files returned */
                char **filename;        /* their names */
        };
        
 (DIR) diff --git a/include/lib9.h b/include/lib9.h
       t@@ -742,6 +742,7 @@ extern        void        abort(void);
        extern        int        p9access(char*, int);
        extern        long        p9alarm(ulong);
        extern        int        await(char*, int);
       +extern        int        awaitnohang(char*, int);
        /* extern        int        bind(char*, char*, int); give up */
        /* extern        int        brk(void*); <unistd.h> */
        extern        int        p9chdir(char*);
       t@@ -790,6 +791,7 @@ extern        int        segfree(void*, ulong);
        extern        int        p9sleep(long);
        /* extern        int        stat(char*, uchar*, int); give up */
        extern        Waitmsg*        p9wait(void);
       +extern        Waitmsg*        waitnohang(void);
        extern        int        p9waitpid(void);
        /* <unistd.h>
        extern        long        write(int, void*, long);
 (DIR) diff --git a/include/plumb.h b/include/plumb.h
       t@@ -42,6 +42,7 @@ struct Plumbattr
        
        int                        plumbsend(int, Plumbmsg*);
        Plumbmsg*        plumbrecv(int);
       +Plumbmsg*        threadplumbrecv(int);
        char*                plumbpack(Plumbmsg*, int*);
        Plumbmsg*        plumbunpack(char*, int);
        Plumbmsg*        plumbunpackpartial(char*, int, int*);
 (DIR) diff --git a/include/thread.h b/include/thread.h
       t@@ -80,8 +80,8 @@ int                nbsendul(Channel *c, unsigned long v);
        int                proccreate(void (*f)(void *arg), void *arg, unsigned int stacksize);
        int                procrfork(void (*f)(void *arg), void *arg, unsigned int stacksize, int flag);
        void**                procdata(void);
       -void                procexec(Channel *, int[3], char *, char *[]);
       -void                procexecl(Channel *, int[3], char *, ...);
       +void                threadexec(Channel *, int[3], char *, char *[]);
       +void                threadexecl(Channel *, int[3], char *, ...);
        int                recv(Channel *c, void *v);
        void*                recvp(Channel *c);
        unsigned long                recvul(Channel *c);
       t@@ -93,6 +93,8 @@ int                threadcreateidle(void (*f)(void*), void*, unsigned int);
        void**                threaddata(void);
        void                threadexits(char *);
        void                threadexitsall(char *);
       +void                threadfdwait(int, int);
       +void                threadfdwaitsetup(void);
        int                threadgetgrp(void);        /* return thread group of current thread */
        char*                threadgetname(void);
        void                threadint(int);        /* interrupt thread */
       t@@ -100,12 +102,20 @@ void                threadintgrp(int);        /* interrupt threads in grp */
        void                threadkill(int);        /* kill thread */
        void                threadkillgrp(int);        /* kill threads in group */
        void                threadmain(int argc, char *argv[]);
       +void                threadfdnoblock(int);
        void                threadnonotes(void);
        int                threadnotify(int (*f)(void*, char*), int in);
        int                threadid(void);
        int                threadpid(int);
       +long                threadread(int, void*, long);
       +long                threadreadn(int, void*, long);
       +int                threadread9pmsg(int, void*, uint);
       +int                threadrecvfd(int);
       +long                threadwrite(int, const void*, long);
       +int                threadsendfd(int, int);
        int                threadsetgrp(int);        /* set thread group, return old */
        void                threadsetname(char *name);
       +void                threadsleep(int);
        Channel*        threadwaitchan(void);
        int        tprivalloc(void);
        void        tprivfree(int);
 (DIR) diff --git a/src/lib9/fmt/LICENSE b/src/lib9/fmt/LICENSE
       t@@ -0,0 +1,19 @@
       +/*
       + * 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.
       +*/
       +
       +This is a Unix port of the Plan 9 formatted I/O package.
       +
       +Please send comments about the packaging
       +to Russ Cox <rsc@post.harvard.edu>.
       +
 (DIR) diff --git a/src/lib9/fmt/NOTICE b/src/lib9/fmt/NOTICE
       t@@ -0,0 +1,19 @@
       +/*
       + * 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.
       +*/
       +
       +This is a Unix port of the Plan 9 formatted I/O package.
       +
       +Please send comments about the packaging
       +to Russ Cox <rsc@post.harvard.edu>.
       +
 (DIR) diff --git a/src/lib9/fmt/README b/src/lib9/fmt/README
       t@@ -0,0 +1,19 @@
       +/*
       + * 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.
       +*/
       +
       +This is a Unix port of the Plan 9 formatted I/O package.
       +
       +Please send comments about the packaging
       +to Russ Cox <rsc@post.harvard.edu>.
       +
 (DIR) diff --git a/src/lib9/fmt/charstod.c b/src/lib9/fmt/charstod.c
       t@@ -0,0 +1,85 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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;
       +}
 (DIR) diff --git a/src/lib9/fmt/dofmt.c b/src/lib9/fmt/dofmt.c
       t@@ -0,0 +1,558 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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;
       +        }
       +        return 0;        /* not reached */
       +}
       +
       +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 charactes
       + */
       +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;
       +        w = f->width;
       +        fl = f->flags;
       +        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(m < me)
       +                        return -1;
       +                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;
       +        w = f->width;
       +        fl = f->flags;
       +        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 p, i;
       +        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(i = 0; i < p; i++)
       +                        if(s[i] == 0)
       +                                break;
       +                return __fmtcpy(f, s, utfnlen(s, i), i);        /* BUG?: won't print a partial rune at end */
       +        }
       +
       +        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[70], *p, *conv;
       +        uvlong vu;
       +        ulong u;
       +        int neg, base, i, n, fl, w, isv;
       +
       +        neg = 0;
       +        fl = f->flags;
       +        isv = 0;
       +        vu = 0;
       +        u = 0;
       +        /*
       +         * Unsigned verbs
       +         */
       +        switch(f->r){
       +        case 'o':
       +        case 'u':
       +        case 'x':
       +        case 'X':
       +                fl |= FmtUnsigned;
       +                break;
       +        }
       +        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";
       +        switch(f->r){
       +        case 'd':
       +        case 'i':
       +                base = 10;
       +                break;
       +        case 'u':
       +                base = 10;
       +                break;
       +        case 'x':
       +                base = 16;
       +                break;
       +        case 'X':
       +                base = 16;
       +                conv = "0123456789ABCDEF";
       +                break;
       +        case 'b':
       +                base = 2;
       +                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;
       +                }
       +        }else{
       +                fl &= ~(FmtSign|FmtSpace);        /* no + for unsigned conversions */
       +        }
       +        p = buf + sizeof buf - 1;
       +        n = 0;
       +        if(isv){
       +                while(vu){
       +                        i = vu % base;
       +                        vu /= base;
       +                        if((fl & FmtComma) && n % 4 == 3){
       +                                *p-- = ',';
       +                                n++;
       +                        }
       +                        *p-- = conv[i];
       +                        n++;
       +                }
       +        }else{
       +                while(u){
       +                        i = u % base;
       +                        u /= base;
       +                        if((fl & FmtComma) && n % 4 == 3){
       +                                *p-- = ',';
       +                                n++;
       +                        }
       +                        *p-- = conv[i];
       +                        n++;
       +                }
       +        }
       +        if(n == 0){
       +                if(!(fl & FmtPrec) || f->prec != 0){
       +                        *p-- = '0';
       +                        n = 1;
       +                }
       +                fl &= ~FmtSharp;
       +        }
       +        for(w = f->prec; n < w && p > buf+3; n++)
       +                *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))){
       +                for(w = f->width; n < w && p > buf+3; n++)
       +                        *p-- = '0';
       +                f->width = 0;
       +        }
       +        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);
       +}
       +
       +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 |= 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;
       +}
 (DIR) diff --git a/src/lib9/fmt/dorfmt.c b/src/lib9/fmt/dorfmt.c
       t@@ -0,0 +1,61 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +/* format the output into f->to and return the number of characters fmted  */
       +
       +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 = f->to;
       +                        rs = 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 = f->to;
       +                        s = 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 = __fmtdispatch(f, fmt, 1);
       +                if(fmt == nil)
       +                        return -1;
       +        }
       +        return 0;                /* not reached */
       +}
 (DIR) diff --git a/src/lib9/fmt/errfmt.c b/src/lib9/fmt/errfmt.c
       t@@ -0,0 +1,28 @@
       +/*
       + * 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 <errno.h>
       +#include <string.h>
       +#include "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +int
       +__errfmt(Fmt *f)
       +{
       +        char *s;
       +
       +        s = strerror(errno);
       +        return fmtstrcpy(f, s);
       +}
 (DIR) diff --git a/src/lib9/fmt/fltfmt.c b/src/lib9/fmt/fltfmt.c
       t@@ -0,0 +1,610 @@
       +/*
       + * 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 <stdio.h>
       +#include <math.h>
       +#include <float.h>
       +#include <string.h>
       +#include <stdlib.h>
       +#include <errno.h>
       +#include <stdarg.h>
       +#include "fmt.h"
       +#include "fmtdef.h"
       +#include "nan.h"
       +
       +enum
       +{
       +        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, 
       +};
       +
       +static double
       +pow10(int n)
       +{
       +        double d;
       +        int neg;
       +
       +        neg = 0;
       +        if(n < 0){
       +                if(n < DBL_MIN_10_EXP){
       +                        return 0.;
       +                }
       +                neg = 1;
       +                n = -n;
       +        }else if(n > DBL_MAX_10_EXP){
       +                return HUGE_VAL;
       +        }
       +        if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
       +                d = pows10[n];
       +        else{
       +                d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
       +                for(;;){
       +                        n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
       +                        if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
       +                                d *= pows10[n];
       +                                break;
       +                        }
       +                        d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
       +                }
       +        }
       +        if(neg){
       +                return 1./d;
       +        }
       +        return d;
       +}
       +
       +static int
       +xadd(char *a, int n, int v)
       +{
       +        char *b;
       +        int c;
       +
       +        if(n < 0 || n >= NSIGNIF)
       +                return 0;
       +        for(b = a+n; b >= a; b--) {
       +                c = *b + v;
       +                if(c <= '9') {
       +                        *b = c;
       +                        return 0;
       +                }
       +                *b = '0';
       +                v = 1;
       +        }
       +        *a = '1';        /* overflow adding */
       +        return 1;
       +}
       +
       +static int
       +xsub(char *a, int n, int v)
       +{
       +        char *b;
       +        int c;
       +
       +        for(b = a+n; b >= a; b--) {
       +                c = *b - v;
       +                if(c >= '0') {
       +                        *b = c;
       +                        return 0;
       +                }
       +                *b = '9';
       +                v = 1;
       +        }
       +        *a = '9';        /* underflow subtracting */
       +        return 1;
       +}
       +
       +static void
       +xaddexp(char *p, int e)
       +{
       +        char se[9];
       +        int i;
       +
       +        *p++ = 'e';
       +        if(e < 0) {
       +                *p++ = '-';
       +                e = -e;
       +        }
       +        i = 0;
       +        while(e) {
       +                se[i++] = e % 10 + '0';
       +                e /= 10;
       +        }
       +        if(i == 0) {
       +                *p++ = '0';
       +        } else {
       +                while(i > 0)
       +                        *p++ = se[--i];
       +        }
       +        *p++ = '\0';
       +}
       +
       +static char*
       +xdodtoa(char *s1, double f, int chr, int prec, int *decpt, int *rsign)
       +{
       +        char s2[NSIGNIF+10];
       +        double g, h;
       +        int e, d, i;
       +        int c2, sign, oerr;
       +
       +        if(chr == 'F')
       +                chr = 'f';
       +        if(prec > NSIGNIF)
       +                prec = NSIGNIF;
       +        if(prec < 0)
       +                prec = 0;
       +        if(__isNaN(f)) {
       +                *decpt = 9999;
       +                *rsign = 0;
       +                strcpy(s1, "nan");
       +                return &s1[3];
       +        }
       +        sign = 0;
       +        if(f < 0) {
       +                f = -f;
       +                sign++;
       +        }
       +        *rsign = sign;
       +        if(__isInf(f, 1) || __isInf(f, -1)) {
       +                *decpt = 9999;
       +                strcpy(s1, "inf");
       +                return &s1[3];
       +        }
       +
       +        e = 0;
       +        g = f;
       +        if(g != 0) {
       +                frexp(f, &e);
       +                e = (int)(e * .301029995664);
       +                if(e >= -150 && e <= +150) {
       +                        d = 0;
       +                        h = f;
       +                } else {
       +                        d = e/2;
       +                        h = f * pow10(-d);
       +                }
       +                g = h * pow10(d-e);
       +                while(g < 1) {
       +                        e--;
       +                        g = h * pow10(d-e);
       +                }
       +                while(g >= 10) {
       +                        e++;
       +                        g = h * pow10(d-e);
       +                }
       +        }
       +
       +        /*
       +         * convert NSIGNIF digits and convert
       +         * back to get accuracy.
       +         */
       +        for(i=0; i<NSIGNIF; i++) {
       +                d = (int)g;
       +                s1[i] = d + '0';
       +                g = (g - d) * 10;
       +        }
       +        s1[i] = 0;
       +
       +        /*
       +         * try decimal rounding to eliminate 9s
       +         */
       +        c2 = prec + 1;
       +        if(chr == 'f')
       +                c2 += e;
       +        oerr = errno;
       +        if(c2 >= NSIGNIF-2) {
       +                strcpy(s2, s1);
       +                d = e;
       +                s1[NSIGNIF-2] = '0';
       +                s1[NSIGNIF-1] = '0';
       +                xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
       +                g = fmtstrtod(s1, nil);
       +                if(g == f)
       +                        goto found;
       +                if(xadd(s1, NSIGNIF-3, 1)) {
       +                        e++;
       +                        xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
       +                }
       +                g = fmtstrtod(s1, nil);
       +                if(g == f)
       +                        goto found;
       +                strcpy(s1, s2);
       +                e = d;
       +        }
       +
       +        /*
       +         * convert back so s1 gets exact answer
       +         */
       +        for(d = 0; d < 10; d++) {
       +                xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
       +                g = fmtstrtod(s1, nil);
       +                if(f > g) {
       +                        if(xadd(s1, NSIGNIF-1, 1))
       +                                e--;
       +                        continue;
       +                }
       +                if(f < g) {
       +                        if(xsub(s1, NSIGNIF-1, 1))
       +                                e++;
       +                        continue;
       +                }
       +                break;
       +        }
       +
       +found:
       +        errno = oerr;
       +
       +        /*
       +         * sign
       +         */
       +        d = 0;
       +        i = 0;
       +
       +        /*
       +         * round & adjust 'f' digits
       +         */
       +        c2 = prec + 1;
       +        if(chr == 'f'){
       +                if(xadd(s1, c2+e, 5))
       +                        e++;
       +                c2 += e;
       +                if(c2 < 0){
       +                        c2 = 0;
       +                        e = -prec - 1;
       +                }
       +        }else{
       +                if(xadd(s1, c2, 5))
       +                        e++;
       +        }
       +        if(c2 > NSIGNIF){
       +                c2 = NSIGNIF;
       +        }
       +
       +        *decpt = e + 1;
       +
       +        /*
       +         * terminate the converted digits
       +         */
       +        s1[c2] = '\0';
       +        return &s1[c2];
       +}
       +
       +/*
       + * this function works like the standard dtoa, if you want it.
       + */
       +#if 0
       +static char*
       +__dtoa(double f, int mode, int ndigits, int *decpt, int *rsign, char **rve)
       +{
       +        static char s2[NSIGNIF + 10];
       +        char *es;
       +        int chr, prec;
       +
       +        switch(mode) {
       +        /* like 'e' */
       +        case 2:
       +        case 4:
       +        case 6:
       +        case 8:
       +                chr = 'e';
       +                break;
       +        /* like 'g' */
       +        case 0:
       +        case 1:
       +        default:
       +                chr = 'g';
       +                break;
       +        /* like 'f' */
       +        case 3:
       +        case 5:
       +        case 7:
       +        case 9:
       +                chr = 'f';
       +                break;
       +        }
       +
       +        if(chr != 'f' && ndigits){
       +                ndigits--;
       +        }
       +        prec = ndigits;
       +        if(prec > NSIGNIF)
       +                prec = NSIGNIF;
       +        if(ndigits == 0)
       +                prec = NSIGNIF;
       +        es = xdodtoa(s2, f, chr, prec, decpt, rsign);
       +
       +        /*
       +         * strip trailing 0
       +         */
       +        for(; es > s2 + 1; es--){
       +                if(es[-1] != '0'){
       +                        break;
       +                }
       +        }
       +        *es = '\0';
       +        if(rve != NULL)
       +                *rve = es;
       +        return s2;
       +}
       +#endif
       +
       +static int
       +fmtzdotpad(Fmt *f, int n, int pt)
       +{
       +        char *t, *s;
       +        int i;
       +        Rune *rt, *rs;
       +
       +        if(f->runes){
       +                rt = (Rune*)f->to;
       +                rs = (Rune*)f->stop;
       +                for(i = 0; i < n; i++){
       +                        if(i == pt){
       +                                FMTRCHAR(f, rt, rs, '.');
       +                        }
       +                        FMTRCHAR(f, rt, rs, '0');
       +                }
       +                f->nfmt += rt - (Rune*)f->to;
       +                f->to = rt;
       +        }else{
       +                t = (char*)f->to;
       +                s = (char*)f->stop;
       +                for(i = 0; i < n; i++){
       +                        if(i == pt){
       +                                FMTCHAR(f, t, s, '.');
       +                        }
       +                        FMTCHAR(f, t, s, '0');
       +                }
       +                f->nfmt += t - (char *)f->to;
       +                f->to = t;
       +        }
       +        return 0;
       +}
       +
       +int
       +__efgfmt(Fmt *fmt)
       +{
       +        double f;
       +        char s1[NSIGNIF+10];
       +        int e, d, n;
       +        int c1, c2, c3, c4, ucase, sign, chr, prec, fl;
       +
       +        f = va_arg(fmt->args, double);
       +        prec = FDEFLT;
       +        fl = fmt->flags;
       +        fmt->flags = 0;
       +        if(fl & FmtPrec)
       +                prec = fmt->prec;
       +        chr = fmt->r;
       +        ucase = 0;
       +        if(chr == 'E'){
       +                chr = 'e';
       +                ucase = 1;
       +        }else if(chr == 'F'){
       +                chr = 'f';
       +                ucase = 1;
       +        }else if(chr == 'G'){
       +                chr = 'g';
       +                ucase = 1;
       +        }
       +        if(prec > 0 && chr == 'g')
       +                prec--;
       +        if(prec < 0)
       +                prec = 0;
       +
       +        xdodtoa(s1, f, chr, prec, &e, &sign);
       +        e--;
       +        if(*s1 == 'i' || *s1 == 'n'){
       +                if(ucase){
       +                        if(*s1 == 'i'){
       +                                strcpy(s1, "INF");
       +                        }else{
       +                                strcpy(s1, "NAN");
       +                        }
       +                }
       +                fmt->flags = fl & (FmtWidth|FmtLeft);
       +                return __fmtcpy(fmt, (const void*)s1, 3, 3);
       +        }
       +
       +        /*
       +         * copy into final place
       +         * c1 digits of leading '0'
       +         * c2 digits from conversion
       +         * c3 digits of trailing '0'
       +         * c4 digits after '.'
       +         */
       +        c1 = 0;
       +        c2 = prec + 1;
       +        c3 = 0;
       +        c4 = prec;
       +        switch(chr) {
       +        default:
       +                chr = 'e';
       +                break;
       +        case 'g':
       +                /*
       +                 * decide on 'e' of 'f' style convers
       +                 */
       +                if(e >= -4 && e <= prec) {
       +                        c1 = -e;
       +                        c4 = prec - e;
       +                        chr = 'h';        /* flag for 'f' style */
       +                }
       +                break;
       +        case 'f':
       +                c1 = -e;
       +                if(c1 > prec)
       +                        c1 = prec + 1;
       +                c2 += e;
       +                break;
       +        }
       +
       +        /*
       +         * clean up c1 c2 and c3
       +         */
       +        if(c1 < 0)
       +                c1 = 0;
       +        if(c2 < 0)
       +                c2 = 0;
       +        if(c2 > NSIGNIF) {
       +                c3 = c2-NSIGNIF;
       +                c2 = NSIGNIF;
       +        }
       +
       +        /*
       +         * trim trailing zeros for %g
       +         */
       +        if(!(fl & FmtSharp)
       +        && (chr == 'g' || chr == 'h')){
       +                if(c4 >= c3){
       +                        c4 -= c3;
       +                        c3 = 0;
       +                }else{
       +                        c3 -= c4;
       +                        c4 = 0;
       +                }
       +                while(c4 && c2 > 1 && s1[c2 - 1] == '0'){
       +                        c4--;
       +                        c2--;
       +                }
       +        }
       +
       +        /*
       +         * calculate the total length
       +         */
       +        n = c1 + c2 + c3;
       +        if(sign || (fl & (FmtSign|FmtSpace)))
       +                n++;
       +        if(c4 || (fl & FmtSharp)){
       +                n++;
       +        }
       +        if(chr == 'e' || chr == 'g'){
       +                n += 4;
       +                if(e >= 100)
       +                        n++;
       +        }
       +
       +        /*
       +         * pad to width if right justified
       +         */
       +        if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){
       +                if(fl & FmtZero){
       +                        c1 += fmt->width - n;
       +                }else{
       +                        if(__fmtpad(fmt, fmt->width - n) < 0){
       +                                return -1;
       +                        }
       +                }
       +        }
       +
       +        /*
       +         * sign
       +         */
       +        d = 0;
       +        if(sign)
       +                d = '-';
       +        else if(fl & FmtSign)
       +                d = '+';
       +        else if(fl & FmtSpace)
       +                d = ' ';
       +        if(d && fmtrune(fmt, d) < 0){
       +                return -1;
       +        }
       +
       +        /*
       +         * copy digits
       +         */
       +        c4 = c1 + c2 + c3 - c4;
       +        if(c1 > 0){
       +                if(fmtzdotpad(fmt, c1, c4) < 0){
       +                        return -1;
       +                }
       +                c4 -= c1;
       +        }
       +        d = 0;
       +        if(c4 >= 0 && c4 < c2){
       +                if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0)
       +                        return -1;
       +                d = c4;
       +                c2 -= c4;
       +                c4 = -1;
       +        }
       +        if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){
       +                return -1;
       +        }
       +        c4 -= c2;
       +        if(c3 > 0){
       +                if(fmtzdotpad(fmt, c3, c4) < 0){
       +                        return -1;
       +                }
       +                c4 -= c3;
       +        }
       +
       +        /*
       +         * strip trailing '0' on g conv
       +         */
       +        if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){
       +                return -1;
       +        }
       +        if(chr == 'e' || chr == 'g') {
       +                d = 0;
       +                if(ucase)
       +                        s1[d++] = 'E';
       +                else
       +                        s1[d++] = 'e';
       +                c1 = e;
       +                if(c1 < 0) {
       +                        s1[d++] = '-';
       +                        c1 = -c1;
       +                } else
       +                        s1[d++] = '+';
       +                if(c1 >= 100) {
       +                        s1[d++] = c1/100 + '0';
       +                        c1 = c1%100;
       +                }
       +                s1[d++] = c1/10 + '0';
       +                s1[d++] = c1%10 + '0';
       +                if(__fmtcpy(fmt, s1, d, d) < 0){
       +                        return -1;
       +                }
       +        }
       +        if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){
       +                if(__fmtpad(fmt, fmt->width - n) < 0){
       +                        return -1;
       +                }
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
       t@@ -0,0 +1,221 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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 */
       +};
       +
       +struct
       +{
       +        /* lock by calling __fmtlock, __fmtunlock */
       +        int        nfmt;
       +        Convfmt        fmt[Maxfmt];
       +} fmtalloc;
       +
       +static Convfmt knownfmt[] = {
       +        ' ',        __flagfmt,
       +        '#',        __flagfmt,
       +        '%',        __percentfmt,
       +        '+',        __flagfmt,
       +        ',',        __flagfmt,
       +        '-',        __flagfmt,
       +        'C',        __runefmt,        /* Plan 9 addition */
       +        'E',        __efgfmt,
       +        'F',        __efgfmt,        /* ANSI only */
       +        'G',        __efgfmt,
       +        'L',        __flagfmt,        /* ANSI only */
       +        'S',        __runesfmt,        /* Plan 9 addition */
       +        'X',        __ifmt,
       +        'b',        __ifmt,                /* Plan 9 addition */
       +        'c',        __charfmt,
       +        'd',        __ifmt,
       +        'e',        __efgfmt,
       +        'f',        __efgfmt,
       +        'g',        __efgfmt,
       +        'h',        __flagfmt,
       +        'i',        __ifmt,                /* ANSI only */
       +        'l',        __flagfmt,
       +        'n',        __countfmt,
       +        'o',        __ifmt,
       +        'p',        __ifmt,
       +        'r',        __errfmt,
       +        's',        __strfmt,
       +        'u',        __flagfmt,        /* in Unix, __ifmt */
       +        '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, Fmts f)
       +{
       +        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;
       +        }
       +}
 (DIR) diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
       t@@ -0,0 +1,121 @@
       +/*
       + * 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.
       + */
       +/*
       + * 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.
       + */
       +#define uchar _fmtuchar
       +#define ushort _fmtushort
       +#define uint _fmtuint
       +#define ulong _fmtulong
       +#define vlong _fmtvlong
       +#define uvlong _fmtuvlong
       +
       +#define USED(x) if(x);else
       +
       +typedef unsigned char                uchar;
       +typedef unsigned short                ushort;
       +typedef unsigned int                uint;
       +typedef unsigned long                ulong;
       +
       +#ifndef NOVLONGS
       +typedef unsigned long long        uvlong;
       +typedef long long                vlong;
       +#endif
       +
       +#define nil                0        /* cannot be ((void*)0) because used for function pointers */
       +
       +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 */
       +};
       +
       +void        *__fmtflush(Fmt*, void*, int);
       +void        *__fmtdispatch(Fmt*, void*, int);
       +int        __floatfmt(Fmt*, double);
       +int        __fmtpad(Fmt*, int);
       +int        __rfmtpad(Fmt*, int);
       +int        __fmtFdFlush(Fmt*);
       +
       +int        __efgfmt(Fmt*);
       +int        __charfmt(Fmt*);
       +int        __runefmt(Fmt*);
       +int        __runesfmt(Fmt*);
       +int        __countfmt(Fmt*);
       +int        __flagfmt(Fmt*);
       +int        __percentfmt(Fmt*);
       +int        __ifmt(Fmt*);
       +int        __strfmt(Fmt*);
       +int        __badfmt(Fmt*);
       +int        __fmtcpy(Fmt*, const void*, int, int);
       +int        __fmtrcpy(Fmt*, const void*, int n);
       +int        __errfmt(Fmt *f);
       +
       +double        __fmtpow10(int);
       +
       +void        __fmtlock(void);
       +void        __fmtunlock(void);
       +
       +#define FMTCHAR(f, t, s, c)\
       +        do{\
       +        if(t + 1 > (char*)s){\
       +                t = __fmtflush(f, t, 1);\
       +                if(t != nil)\
       +                        s = f->stop;\
       +                else\
       +                        return -1;\
       +        }\
       +        *t++ = c;\
       +        }while(0)
       +
       +#define FMTRCHAR(f, t, s, c)\
       +        do{\
       +        if(t + 1 > (Rune*)s){\
       +                t = __fmtflush(f, t, sizeof(Rune));\
       +                if(t != nil)\
       +                        s = 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 = __fmtflush(f, t, _runelen);\
       +                if(t != nil)\
       +                        s = f->stop;\
       +                else\
       +                        return -1;\
       +        }\
       +        if(r < Runeself)\
       +                *t++ = r;\
       +        else{\
       +                _rune = r;\
       +                t += runetochar(t, &_rune);\
       +        }\
       +        }while(0)
 (DIR) diff --git a/src/lib9/fmt/fmtfd.c b/src/lib9/fmt/fmtfd.c
       t@@ -0,0 +1,46 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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*)fd;
       +        f->nfmt = 0;
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/fmt/fmtfdflush.c b/src/lib9/fmt/fmtfdflush.c
       t@@ -0,0 +1,33 @@
       +/*
       + * 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 <unistd.h>
       +#include "fmt.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((int)f->farg, f->start, n) != n)
       +                return 0;
       +        f->to = f->start;
       +        return 1;
       +}
 (DIR) diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
       t@@ -0,0 +1,28 @@
       +/*
       + * 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 "fmt.h"
       +#include "fmtdef.h"
       +
       +void
       +__fmtlock(void)
       +{
       +        ;
       +}
       +
       +void
       +__fmtunlock(void)
       +{
       +        ;
       +}
 (DIR) diff --git a/src/lib9/fmt/fmtprint.c b/src/lib9/fmt/fmtprint.c
       t@@ -0,0 +1,47 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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 = f->args;
       +        va_start(f->args, fmt);
       +        n = dofmt(f, fmt);
       +        va_end(f->args);
       +        f->flags = 0;
       +        f->width = 0;
       +        f->prec = 0;
       +        f->args = va;
       +        if(n >= 0)
       +                return 0;
       +        return n;
       +}
       +
 (DIR) diff --git a/src/lib9/fmt/fmtquote.c b/src/lib9/fmt/fmtquote.c
       t@@ -0,0 +1,262 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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-=w){
       +                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++;
       +        }
       +}
       +
       +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;
       +
       +        w = f->width;
       +        fl = f->flags;
       +        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 outlen;
       +        Rune *r;
       +        char *s;
       +        Quoteinfo q;
       +
       +        f->flags &= ~FmtPrec;        /* ignored for %q %Q, so disable for %s %S in easy case */
       +        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, -1, 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;
       +}
 (DIR) diff --git a/src/lib9/fmt/fmtrune.c b/src/lib9/fmt/fmtrune.c
       t@@ -0,0 +1,40 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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;
       +}
 (DIR) diff --git a/src/lib9/fmt/fmtstr.c b/src/lib9/fmt/fmtstr.c
       t@@ -0,0 +1,65 @@
       +/*
       + * 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 <stdlib.h>
       +#include "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +static int
       +fmtStrFlush(Fmt *f)
       +{
       +        char *s;
       +        int n;
       +
       +        n = (int)f->farg;
       +        n += 256;
       +        f->farg = (void*)n;
       +        s = (char*)f->start;
       +        f->start = realloc(s, n);
       +        if(f->start == nil){
       +                f->start = s;
       +                return 0;
       +        }
       +        f->to = (char*)f->start + ((char*)f->to - s);
       +        f->stop = (char*)f->start + n - 1;
       +        return 1;
       +}
       +
       +int
       +fmtstrinit(Fmt *f)
       +{
       +        int n;
       +
       +        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*)n;
       +        f->nfmt = 0;
       +        return 0;
       +}
       +
       +char*
       +fmtstrflush(Fmt *f)
       +{
       +        *(char*)f->to = '\0';
       +        f->to = f->start;
       +        return (char*)f->start;
       +}
 (DIR) diff --git a/src/lib9/fmt/fmtvprint.c b/src/lib9/fmt/fmtvprint.c
       t@@ -0,0 +1,46 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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 = f->args;
       +        f->args = args;
       +        n = dofmt(f, fmt);
       +        f->flags = 0;
       +        f->width = 0;
       +        f->prec = 0;
       +        f->args = va;
       +        if(n >= 0)
       +                return 0;
       +        return n;
       +}
       +
 (DIR) diff --git a/src/lib9/fmt/fprint.c b/src/lib9/fmt/fprint.c
       t@@ -0,0 +1,28 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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;
       +}
 (DIR) diff --git a/src/lib9/fmt/mkfile b/src/lib9/fmt/mkfile
       t@@ -0,0 +1,57 @@
       +PLAN9=../..
       +<$PLAN9/src/mkhdr
       +
       +LIB=libfmt.a
       +
       +NUM=\
       +        charstod.$O\
       +        pow10.$O\
       +
       +# Could add errfmt, but we want to pick it up from lib9 instead.
       +OFILES=\
       +        dofmt.$O\
       +        errfmt.$O\
       +        fltfmt.$O\
       +        fmt.$O\
       +        fmtfd.$O\
       +        fmtfdflush.$O\
       +        fmtlock.$O\
       +        fmtprint.$O\
       +        fmtquote.$O\
       +        fmtrune.$O\
       +        fmtstr.$O\
       +        fmtvprint.$O\
       +        fprint.$O\
       +        nan64.$O\
       +        print.$O\
       +        runefmtstr.$O\
       +        runeseprint.$O\
       +        runesmprint.$O\
       +        runesnprint.$O\
       +        runesprint.$O\
       +        runevseprint.$O\
       +        runevsmprint.$O\
       +        runevsnprint.$O\
       +        seprint.$O\
       +        smprint.$O\
       +        snprint.$O\
       +        sprint.$O\
       +        strtod.$O\
       +        vfprint.$O\
       +        vseprint.$O\
       +        vsmprint.$O\
       +        vsnprint.$O\
       +        $NUM\
       +
       +HFILES=\
       +        fmtdef.h\
       +        $PLAN9/include/fmt.h\
       +
       +<$PLAN9/src/mksyslib
       +
       +$NAN.$O: nan.h
       +strtod.$O: nan.h
       +
       +test: $LIB test.$O
       +        $CC -o test test.$O $LIB -L$PLAN9/lib -lutf
       +
 (DIR) diff --git a/src/lib9/fmt/nan.h b/src/lib9/fmt/nan.h
       t@@ -0,0 +1,4 @@
       +extern double __NaN(void);
       +extern double __Inf(int);
       +extern int __isNaN(double);
       +extern int __isInf(double, int);
 (DIR) diff --git a/src/lib9/fmt/nan64.c b/src/lib9/fmt/nan64.c
       t@@ -0,0 +1,76 @@
       +/*
       + * 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 "nan.h"
       +
       +#ifdef __APPLE__
       +#define _NEEDLL
       +#endif
       +
       +typedef unsigned long long uvlong;
       +typedef unsigned long ulong;
       +
       +#ifdef _NEEDLL
       +static uvlong uvnan    = 0x7FF0000000000001LL;
       +static uvlong uvinf    = 0x7FF0000000000000LL;
       +static uvlong uvneginf = 0xFFF0000000000000LL;
       +#else
       +static uvlong uvnan    = 0x7FF0000000000001;
       +static uvlong uvinf    = 0x7FF0000000000000;
       +static uvlong uvneginf = 0xFFF0000000000000;
       +#endif
       +
       +double
       +__NaN(void)
       +{
       +        uvlong *p;
       +
       +        /* gcc complains about "return *(double*)&uvnan;" */
       +        p = &uvnan;
       +        return *(double*)p;
       +}
       +
       +int
       +__isNaN(double d)
       +{
       +        uvlong x;
       +        double *p;
       +
       +        p = &d;
       +        x = *(uvlong*)p;
       +        return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
       +}
       +
       +double
       +__Inf(int sign)
       +{
       +        uvlong *p;
       +
       +        if(sign < 0)
       +                p = &uvinf;
       +        else
       +                p = &uvneginf;
       +        return *(double*)p;
       +}
       +
       +int
       +__isInf(double d, int sign)
       +{
       +        uvlong x;
       +        double *p;
       +
       +        p = &d;
       +        x = *(uvlong*)p;
       +        if(sign == 0)
       +                return x==uvinf || x==uvneginf;
       +        else if(sign > 0)
       +                return x==uvinf;
       +        else
       +                return x==uvneginf;
       +}
       +
       +
 (DIR) diff --git a/src/lib9/fmt/pow10.c b/src/lib9/fmt/pow10.c
       t@@ -0,0 +1,57 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.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);
       +}
 (DIR) diff --git a/src/lib9/fmt/print.c b/src/lib9/fmt/print.c
       t@@ -0,0 +1,28 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +
       +int
       +print(char *fmt, ...)
       +{
       +        int n;
       +        va_list args;
       +
       +        va_start(args, fmt);
       +        n = vfprint(1, fmt, args);
       +        va_end(args);
       +        return n;
       +}
 (DIR) diff --git a/src/lib9/fmt/runefmtstr.c b/src/lib9/fmt/runefmtstr.c
       t@@ -0,0 +1,65 @@
       +/*
       + * 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 <stdlib.h>
       +#include "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +static int
       +runeFmtStrFlush(Fmt *f)
       +{
       +        Rune *s;
       +        int n;
       +
       +        n = (int)f->farg;
       +        n += 256;
       +        f->farg = (void*)n;
       +        s = (Rune*)f->start;
       +        f->start = realloc(s, sizeof(Rune)*n);
       +        if(f->start == nil){
       +                f->start = s;
       +                return 0;
       +        }
       +        f->to = (Rune*)f->start + ((Rune*)f->to - s);
       +        f->stop = (Rune*)f->start + n - 1;
       +        return 1;
       +}
       +
       +int
       +runefmtstrinit(Fmt *f)
       +{
       +        int n;
       +
       +        f->runes = 1;
       +        n = 32;
       +        f->start = malloc(sizeof(Rune)*n);
       +        if(f->start == nil)
       +                return -1;
       +        f->to = f->start;
       +        f->stop = (Rune*)f->start + n - 1;
       +        f->flush = runeFmtStrFlush;
       +        f->farg = (void*)n;
       +        f->nfmt = 0;
       +        return 0;
       +}
       +
       +Rune*
       +runefmtstrflush(Fmt *f)
       +{
       +        *(Rune*)f->to = '\0';
       +        f->to = f->start;
       +        return f->start;
       +}
 (DIR) diff --git a/src/lib9/fmt/runeseprint.c b/src/lib9/fmt/runeseprint.c
       t@@ -0,0 +1,30 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +Rune*
       +runeseprint(Rune *buf, Rune *e, char *fmt, ...)
       +{
       +        Rune *p;
       +        va_list args;
       +
       +        va_start(args, fmt);
       +        p = runevseprint(buf, e, fmt, args);
       +        va_end(args);
       +        return p;
       +}
 (DIR) diff --git a/src/lib9/fmt/runesmprint.c b/src/lib9/fmt/runesmprint.c
       t@@ -0,0 +1,30 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +Rune*
       +runesmprint(char *fmt, ...)
       +{
       +        va_list args;
       +        Rune *p;
       +
       +        va_start(args, fmt);
       +        p = runevsmprint(fmt, args);
       +        va_end(args);
       +        return p;
       +}
 (DIR) diff --git a/src/lib9/fmt/runesnprint.c b/src/lib9/fmt/runesnprint.c
       t@@ -0,0 +1,31 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +int
       +runesnprint(Rune *buf, int len, char *fmt, ...)
       +{
       +        int n;
       +        va_list args;
       +
       +        va_start(args, fmt);
       +        n = runevsnprint(buf, len, fmt, args);
       +        va_end(args);
       +        return n;
       +}
       +
 (DIR) diff --git a/src/lib9/fmt/runesprint.c b/src/lib9/fmt/runesprint.c
       t@@ -0,0 +1,30 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +int
       +runesprint(Rune *buf, char *fmt, ...)
       +{
       +        int n;
       +        va_list args;
       +
       +        va_start(args, fmt);
       +        n = runevsnprint(buf, 256, fmt, args);
       +        va_end(args);
       +        return n;
       +}
 (DIR) diff --git a/src/lib9/fmt/runevseprint.c b/src/lib9/fmt/runevseprint.c
       t@@ -0,0 +1,39 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +Rune*
       +runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
       +{
       +        Fmt f;
       +
       +        if(e <= buf)
       +                return nil;
       +        f.runes = 1;
       +        f.start = buf;
       +        f.to = buf;
       +        f.stop = e - 1;
       +        f.flush = nil;
       +        f.farg = nil;
       +        f.nfmt = 0;
       +        f.args = args;
       +        dofmt(&f, fmt);
       +        *(Rune*)f.to = '\0';
       +        return (Rune*)f.to;
       +}
       +
 (DIR) diff --git a/src/lib9/fmt/runevsmprint.c b/src/lib9/fmt/runevsmprint.c
       t@@ -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 <stdlib.h>
       +#include "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +/*
       + * print into an allocated string buffer
       + */
       +Rune*
       +runevsmprint(char *fmt, va_list args)
       +{
       +        Fmt f;
       +        int n;
       +
       +        if(runefmtstrinit(&f) < 0)
       +                return nil;
       +        f.args = args;
       +        n = dofmt(&f, fmt);
       +        if(n < 0)
       +                return nil;
       +        *(Rune*)f.to = '\0';
       +        return (Rune*)f.start;
       +}
 (DIR) diff --git a/src/lib9/fmt/runevsnprint.c b/src/lib9/fmt/runevsnprint.c
       t@@ -0,0 +1,38 @@
       +/*
       + * 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 "utf.h"
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +int
       +runevsnprint(Rune *buf, int len, char *fmt, va_list args)
       +{
       +        Fmt f;
       +
       +        if(len <= 0)
       +                return -1;
       +        f.runes = 1;
       +        f.start = buf;
       +        f.to = buf;
       +        f.stop = buf + len - 1;
       +        f.flush = nil;
       +        f.farg = nil;
       +        f.nfmt = 0;
       +        f.args = args;
       +        dofmt(&f, fmt);
       +        *(Rune*)f.to = '\0';
       +        return (Rune*)f.to - buf;
       +}
 (DIR) diff --git a/src/lib9/fmt/seprint.c b/src/lib9/fmt/seprint.c
       t@@ -0,0 +1,27 @@
       +/*
       + * 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 "fmt.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;
       +}
 (DIR) diff --git a/src/lib9/fmt/smprint.c b/src/lib9/fmt/smprint.c
       t@@ -0,0 +1,27 @@
       +/*
       + * 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 "fmt.h"
       +
       +char*
       +smprint(char *fmt, ...)
       +{
       +        va_list args;
       +        char *p;
       +
       +        va_start(args, fmt);
       +        p = vsmprint(fmt, args);
       +        va_end(args);
       +        return p;
       +}
 (DIR) diff --git a/src/lib9/fmt/snprint.c b/src/lib9/fmt/snprint.c
       t@@ -0,0 +1,28 @@
       +/*
       + * 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 "fmt.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;
       +}
       +
 (DIR) diff --git a/src/lib9/fmt/sprint.c b/src/lib9/fmt/sprint.c
       t@@ -0,0 +1,27 @@
       +/*
       + * 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 "fmt.h"
       +
       +int
       +sprint(char *buf, char *fmt, ...)
       +{
       +        int n;
       +        va_list args;
       +
       +        va_start(args, fmt);
       +        n = vsnprint(buf, 65536, fmt, args);        /* big number, but sprint is deprecated anyway */
       +        va_end(args);
       +        return n;
       +}
 (DIR) diff --git a/src/lib9/fmt/strtod.c b/src/lib9/fmt/strtod.c
       t@@ -0,0 +1,539 @@
       +/*
       + * 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 <stdlib.h>
       +#include <math.h>
       +#include <ctype.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <errno.h>
       +#include "fmt.h"
       +#include "nan.h"
       +
       +#ifndef nelem
       +#define nelem(x)        (sizeof(x)/sizeof *(x))
       +#endif
       +#define nil ((void*)0)
       +#define ulong _fmtulong
       +typedef unsigned long ulong;
       +
       +static ulong
       +umuldiv(ulong a, ulong b, ulong c)
       +{
       +        double d;
       +
       +        d = ((double)a * (double)b) / (double)c;
       +        if(d >= 4294967295.)
       +                d = 4294967295.;
       +        return (ulong)d;
       +}
       +
       +/*
       + * This routine will convert to arbitrary precision
       + * floating point entirely in multi-precision fixed.
       + * The answer is the closest floating point number to
       + * the given decimal number. Exactly half way are
       + * rounded ala ieee rules.
       + * Method is to scale input decimal between .500 and .999...
       + * with external power of 2, then binary search for the
       + * closest mantissa to this decimal number.
       + * Nmant is is the required precision. (53 for ieee dp)
       + * Nbits is the max number of bits/word. (must be <= 28)
       + * Prec is calculated - the number of words of fixed mantissa.
       + */
       +enum
       +{
       +        Nbits        = 28,                                /* bits safely represented in a ulong */
       +        Nmant        = 53,                                /* bits of precision required */
       +        Prec        = (Nmant+Nbits+1)/Nbits,        /* words of Nbits each to represent mantissa */
       +        Sigbit        = 1<<(Prec*Nbits-Nmant),        /* first significant bit of Prec-th word */
       +        Ndig        = 1500,
       +        One        = (ulong)(1<<Nbits),
       +        Half        = (ulong)(One>>1),
       +        Maxe        = 310,
       +
       +        Fsign        = 1<<0,                /* found - */
       +        Fesign        = 1<<1,                /* found e- */
       +        Fdpoint        = 1<<2,                /* found . */
       +
       +        S0        = 0,                /* _                _S0        +S1        #S2        .S3 */
       +        S1,                        /* _+                #S2        .S3 */
       +        S2,                        /* _+#                #S2        .S4        eS5 */
       +        S3,                        /* _+.                #S4 */
       +        S4,                        /* _+#.#        #S4        eS5 */
       +        S5,                        /* _+#.#e        +S6        #S7 */
       +        S6,                        /* _+#.#e+        #S7 */
       +        S7,                        /* _+#.#e+#        #S7 */
       +};
       +
       +static        int        xcmp(char*, char*);
       +static        int        fpcmp(char*, ulong*);
       +static        void        frnorm(ulong*);
       +static        void        divascii(char*, int*, int*, int*);
       +static        void        mulascii(char*, int*, int*, int*);
       +
       +typedef        struct        Tab        Tab;
       +struct        Tab
       +{
       +        int        bp;
       +        int        siz;
       +        char*        cmp;
       +};
       +
       +double
       +fmtstrtod(const char *as, char **aas)
       +{
       +        int na, ex, dp, bp, c, i, flag, state;
       +        ulong low[Prec], hig[Prec], mid[Prec];
       +        double d;
       +        char *s, a[Ndig];
       +
       +        flag = 0;        /* Fsign, Fesign, Fdpoint */
       +        na = 0;                /* number of digits of a[] */
       +        dp = 0;                /* na of decimal point */
       +        ex = 0;                /* exonent */
       +
       +        state = S0;
       +        for(s=(char*)as;; s++) {
       +                c = *s;
       +                if(c >= '0' && c <= '9') {
       +                        switch(state) {
       +                        case S0:
       +                        case S1:
       +                        case S2:
       +                                state = S2;
       +                                break;
       +                        case S3:
       +                        case S4:
       +                                state = S4;
       +                                break;
       +
       +                        case S5:
       +                        case S6:
       +                        case S7:
       +                                state = S7;
       +                                ex = ex*10 + (c-'0');
       +                                continue;
       +                        }
       +                        if(na == 0 && c == '0') {
       +                                dp--;
       +                                continue;
       +                        }
       +                        if(na < Ndig-50)
       +                                a[na++] = c;
       +                        continue;
       +                }
       +                switch(c) {
       +                case '\t':
       +                case '\n':
       +                case '\v':
       +                case '\f':
       +                case '\r':
       +                case ' ':
       +                        if(state == S0)
       +                                continue;
       +                        break;
       +                case '-':
       +                        if(state == S0)
       +                                flag |= Fsign;
       +                        else
       +                                flag |= Fesign;
       +                case '+':
       +                        if(state == S0)
       +                                state = S1;
       +                        else
       +                        if(state == S5)
       +                                state = S6;
       +                        else
       +                                break;        /* syntax */
       +                        continue;
       +                case '.':
       +                        flag |= Fdpoint;
       +                        dp = na;
       +                        if(state == S0 || state == S1) {
       +                                state = S3;
       +                                continue;
       +                        }
       +                        if(state == S2) {
       +                                state = S4;
       +                                continue;
       +                        }
       +                        break;
       +                case 'e':
       +                case 'E':
       +                        if(state == S2 || state == S4) {
       +                                state = S5;
       +                                continue;
       +                        }
       +                        break;
       +                }
       +                break;
       +        }
       +
       +        /*
       +         * clean up return char-pointer
       +         */
       +        switch(state) {
       +        case S0:
       +                if(xcmp(s, "nan") == 0) {
       +                        if(aas != nil)
       +                                *aas = s+3;
       +                        goto retnan;
       +                }
       +        case S1:
       +                if(xcmp(s, "infinity") == 0) {
       +                        if(aas != nil)
       +                                *aas = s+8;
       +                        goto retinf;
       +                }
       +                if(xcmp(s, "inf") == 0) {
       +                        if(aas != nil)
       +                                *aas = s+3;
       +                        goto retinf;
       +                }
       +        case S3:
       +                if(aas != nil)
       +                        *aas = (char*)as;
       +                goto ret0;        /* no digits found */
       +        case S6:
       +                s--;                /* back over +- */
       +        case S5:
       +                s--;                /* back over e */
       +                break;
       +        }
       +        if(aas != nil)
       +                *aas = s;
       +
       +        if(flag & Fdpoint)
       +        while(na > 0 && a[na-1] == '0')
       +                na--;
       +        if(na == 0)
       +                goto ret0;        /* zero */
       +        a[na] = 0;
       +        if(!(flag & Fdpoint))
       +                dp = na;
       +        if(flag & Fesign)
       +                ex = -ex;
       +        dp += ex;
       +        if(dp < -Maxe){
       +                errno = ERANGE;
       +                goto ret0;        /* underflow by exp */
       +        } else
       +        if(dp > +Maxe)
       +                goto retinf;        /* overflow by exp */
       +
       +        /*
       +         * normalize the decimal ascii number
       +         * to range .[5-9][0-9]* e0
       +         */
       +        bp = 0;                /* binary exponent */
       +        while(dp > 0)
       +                divascii(a, &na, &dp, &bp);
       +        while(dp < 0 || a[0] < '5')
       +                mulascii(a, &na, &dp, &bp);
       +
       +        /* close approx by naive conversion */
       +        mid[0] = 0;
       +        mid[1] = 1;
       +        for(i=0; c=a[i]; i++) {
       +                mid[0] = mid[0]*10 + (c-'0');
       +                mid[1] = mid[1]*10;
       +                if(i >= 8)
       +                        break;
       +        }
       +        low[0] = umuldiv(mid[0], One, mid[1]);
       +        hig[0] = umuldiv(mid[0]+1, One, mid[1]);
       +        for(i=1; i<Prec; i++) {
       +                low[i] = 0;
       +                hig[i] = One-1;
       +        }
       +
       +        /* binary search for closest mantissa */
       +        for(;;) {
       +                /* mid = (hig + low) / 2 */
       +                c = 0;
       +                for(i=0; i<Prec; i++) {
       +                        mid[i] = hig[i] + low[i];
       +                        if(c)
       +                                mid[i] += One;
       +                        c = mid[i] & 1;
       +                        mid[i] >>= 1;
       +                }
       +                frnorm(mid);
       +
       +                /* compare */
       +                c = fpcmp(a, mid);
       +                if(c > 0) {
       +                        c = 1;
       +                        for(i=0; i<Prec; i++)
       +                                if(low[i] != mid[i]) {
       +                                        c = 0;
       +                                        low[i] = mid[i];
       +                                }
       +                        if(c)
       +                                break;        /* between mid and hig */
       +                        continue;
       +                }
       +                if(c < 0) {
       +                        for(i=0; i<Prec; i++)
       +                                hig[i] = mid[i];
       +                        continue;
       +                }
       +
       +                /* only hard part is if even/odd roundings wants to go up */
       +                c = mid[Prec-1] & (Sigbit-1);
       +                if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
       +                        mid[Prec-1] -= c;
       +                break;        /* exactly mid */
       +        }
       +
       +        /* normal rounding applies */
       +        c = mid[Prec-1] & (Sigbit-1);
       +        mid[Prec-1] -= c;
       +        if(c >= Sigbit/2) {
       +                mid[Prec-1] += Sigbit;
       +                frnorm(mid);
       +        }
       +        goto out;
       +
       +ret0:
       +        return 0;
       +
       +retnan:
       +        return __NaN();
       +
       +retinf:
       +        /*
       +         * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
       +        errno = ERANGE;
       +        if(flag & Fsign)
       +                return -HUGE_VAL;
       +        return HUGE_VAL;
       +
       +out:
       +        d = 0;
       +        for(i=0; i<Prec; i++)
       +                d = d*One + mid[i];
       +        if(flag & Fsign)
       +                d = -d;
       +        d = ldexp(d, bp - Prec*Nbits);
       +        if(d == 0){        /* underflow */
       +                errno = ERANGE;
       +        }
       +        return d;
       +}
       +
       +static void
       +frnorm(ulong *f)
       +{
       +        int i, c;
       +
       +        c = 0;
       +        for(i=Prec-1; i>0; i--) {
       +                f[i] += c;
       +                c = f[i] >> Nbits;
       +                f[i] &= One-1;
       +        }
       +        f[0] += c;
       +}
       +
       +static int
       +fpcmp(char *a, ulong* f)
       +{
       +        ulong tf[Prec];
       +        int i, d, c;
       +
       +        for(i=0; i<Prec; i++)
       +                tf[i] = f[i];
       +
       +        for(;;) {
       +                /* tf *= 10 */
       +                for(i=0; i<Prec; i++)
       +                        tf[i] = tf[i]*10;
       +                frnorm(tf);
       +                d = (tf[0] >> Nbits) + '0';
       +                tf[0] &= One-1;
       +
       +                /* compare next digit */
       +                c = *a;
       +                if(c == 0) {
       +                        if('0' < d)
       +                                return -1;
       +                        if(tf[0] != 0)
       +                                goto cont;
       +                        for(i=1; i<Prec; i++)
       +                                if(tf[i] != 0)
       +                                        goto cont;
       +                        return 0;
       +                }
       +                if(c > d)
       +                        return +1;
       +                if(c < d)
       +                        return -1;
       +                a++;
       +        cont:;
       +        }
       +        return 0;
       +}
       +
       +static void
       +divby(char *a, int *na, int b)
       +{
       +        int n, c;
       +        char *p;
       +
       +        p = a;
       +        n = 0;
       +        while(n>>b == 0) {
       +                c = *a++;
       +                if(c == 0) {
       +                        while(n) {
       +                                c = n*10;
       +                                if(c>>b)
       +                                        break;
       +                                n = c;
       +                        }
       +                        goto xx;
       +                }
       +                n = n*10 + c-'0';
       +                (*na)--;
       +        }
       +        for(;;) {
       +                c = n>>b;
       +                n -= c<<b;
       +                *p++ = c + '0';
       +                c = *a++;
       +                if(c == 0)
       +                        break;
       +                n = n*10 + c-'0';
       +        }
       +        (*na)++;
       +xx:
       +        while(n) {
       +                n = n*10;
       +                c = n>>b;
       +                n -= c<<b;
       +                *p++ = c + '0';
       +                (*na)++;
       +        }
       +        *p = 0;
       +}
       +
       +static        Tab        tab1[] =
       +{
       +         1,  0, "",
       +         3,  1, "7",
       +         6,  2, "63",
       +         9,  3, "511",
       +        13,  4, "8191",
       +        16,  5, "65535",
       +        19,  6, "524287",
       +        23,  7, "8388607",
       +        26,  8, "67108863",
       +        27,  9, "134217727",
       +};
       +
       +static void
       +divascii(char *a, int *na, int *dp, int *bp)
       +{
       +        int b, d;
       +        Tab *t;
       +
       +        d = *dp;
       +        if(d >= (int)(nelem(tab1)))
       +                d = (int)(nelem(tab1))-1;
       +        t = tab1 + d;
       +        b = t->bp;
       +        if(memcmp(a, t->cmp, t->siz) > 0)
       +                d--;
       +        *dp -= d;
       +        *bp += b;
       +        divby(a, na, b);
       +}
       +
       +static void
       +mulby(char *a, char *p, char *q, int b)
       +{
       +        int n, c;
       +
       +        n = 0;
       +        *p = 0;
       +        for(;;) {
       +                q--;
       +                if(q < a)
       +                        break;
       +                c = *q - '0';
       +                c = (c<<b) + n;
       +                n = c/10;
       +                c -= n*10;
       +                p--;
       +                *p = c + '0';
       +        }
       +        while(n) {
       +                c = n;
       +                n = c/10;
       +                c -= n*10;
       +                p--;
       +                *p = c + '0';
       +        }
       +}
       +
       +static        Tab        tab2[] =
       +{
       +         1,  1, "",                                /* dp = 0-0 */
       +         3,  3, "125",
       +         6,  5, "15625",
       +         9,  7, "1953125",
       +        13, 10, "1220703125",
       +        16, 12, "152587890625",
       +        19, 14, "19073486328125",
       +        23, 17, "11920928955078125",
       +        26, 19, "1490116119384765625",
       +        27, 19, "7450580596923828125",                /* dp 8-9 */
       +};
       +
       +static void
       +mulascii(char *a, int *na, int *dp, int *bp)
       +{
       +        char *p;
       +        int d, b;
       +        Tab *t;
       +
       +        d = -*dp;
       +        if(d >= (int)(nelem(tab2)))
       +                d = (int)(nelem(tab2))-1;
       +        t = tab2 + d;
       +        b = t->bp;
       +        if(memcmp(a, t->cmp, t->siz) < 0)
       +                d--;
       +        p = a + *na;
       +        *bp -= b;
       +        *dp += d;
       +        *na += d;
       +        mulby(a, p+d, p, b);
       +}
       +
       +static int
       +xcmp(char *a, char *b)
       +{
       +        int c1, c2;
       +
       +        while(c1 = *b++) {
       +                c2 = *a++;
       +                if(isupper(c2))
       +                        c2 = tolower(c2);
       +                if(c1 != c2)
       +                        return 1;
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/fmt/strtod.h b/src/lib9/fmt/strtod.h
       t@@ -0,0 +1,4 @@
       +extern double __NaN(void);
       +extern double __Inf(int);
       +extern double __isNaN(double);
       +extern double __isInf(double, int);
 (DIR) diff --git a/src/lib9/fmt/test.c b/src/lib9/fmt/test.c
       t@@ -0,0 +1,39 @@
       +/*
       + * 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 <utf.h>
       +#include "fmt.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 %.18\n", 2e25, 2e25);
       +        print("%2.18g\n", 1.0);
       +        print("%f\n", 3.1415927/4);
       +        print("%d\n", 23);
       +        print("%i\n", 23);
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/fmt/vfprint.c b/src/lib9/fmt/vfprint.c
       t@@ -0,0 +1,31 @@
       +/*
       + * 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 "fmt.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));
       +        f.args = args;
       +        n = dofmt(&f, fmt);
       +        if(n > 0 && __fmtFdFlush(&f) == 0)
       +                return -1;
       +        return n;
       +}
 (DIR) diff --git a/src/lib9/fmt/vseprint.c b/src/lib9/fmt/vseprint.c
       t@@ -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 "fmt.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;
       +        f.args = args;
       +        dofmt(&f, fmt);
       +        *(char*)f.to = '\0';
       +        return (char*)f.to;
       +}
       +
 (DIR) diff --git a/src/lib9/fmt/vsmprint.c b/src/lib9/fmt/vsmprint.c
       t@@ -0,0 +1,36 @@
       +/*
       + * 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 <stdlib.h>
       +#include <stdarg.h>
       +#include "fmt.h"
       +#include "fmtdef.h"
       +
       +/*
       + * print into an allocated string buffer
       + */
       +char*
       +vsmprint(char *fmt, va_list args)
       +{
       +        Fmt f;
       +        int n;
       +
       +        if(fmtstrinit(&f) < 0)
       +                return nil;
       +        f.args = args;
       +        n = dofmt(&f, fmt);
       +        if(n < 0)
       +                return nil;
       +        *(char*)f.to = '\0';
       +        return (char*)f.start;
       +}
 (DIR) diff --git a/src/lib9/fmt/vsnprint.c b/src/lib9/fmt/vsnprint.c
       t@@ -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 <stdlib.h>
       +#include <stdarg.h>
       +#include "fmt.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;
       +        f.args = args;
       +        dofmt(&f, fmt);
       +        *(char*)f.to = '\0';
       +        return (char*)f.to - buf;
       +}
 (DIR) diff --git a/src/lib9/utf/LICENSE b/src/lib9/utf/LICENSE
       t@@ -0,0 +1,13 @@
       +/*
       + * 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.
       + */
 (DIR) diff --git a/src/lib9/utf/NOTICE b/src/lib9/utf/NOTICE
       t@@ -0,0 +1,13 @@
       +/*
       + * 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.
       + */
 (DIR) diff --git a/src/lib9/utf/README b/src/lib9/utf/README
       t@@ -0,0 +1,13 @@
       +/*
       + * 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.
       + */
 (DIR) diff --git a/src/lib9/utf/lib9.h b/src/lib9/utf/lib9.h
       t@@ -0,0 +1,17 @@
       +#include <string.h>
       +#include "utf.h"
       +
       +#define nil ((void*)0)
       +
       +#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;
       +
 (DIR) diff --git a/src/lib9/utf/mkfile b/src/lib9/utf/mkfile
       t@@ -0,0 +1,31 @@
       +PLAN9=../..
       +<$PLAN9/src/mkhdr
       +
       +LIB=libutf.a
       +
       +OFILES=\
       +        rune.$O\
       +        runestrcat.$O\
       +        runestrchr.$O\
       +        runestrcmp.$O\
       +        runestrcpy.$O\
       +        runestrdup.$O\
       +        runestrlen.$O\
       +        runestrecpy.$O\
       +        runestrncat.$O\
       +        runestrncmp.$O\
       +        runestrncpy.$O\
       +        runestrrchr.$O\
       +        runestrstr.$O\
       +        runetype.$O\
       +        utfecpy.$O\
       +        utflen.$O\
       +        utfnlen.$O\
       +        utfrrune.$O\
       +        utfrune.$O\
       +        utfutf.$O\
       +
       +HFILES=\
       +        $PLAN9/include/utf.h\
       +
       +<$PLAN9/src/mksyslib
 (DIR) diff --git a/src/lib9/utf/rune.c b/src/lib9/utf/rune.c
       t@@ -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 "utf.h"
       +#include "utfdef.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;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrcat.c b/src/lib9/utf/runestrcat.c
       t@@ -0,0 +1,25 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrcat(Rune *s1, Rune *s2)
       +{
       +
       +        runestrcpy(runestrchr(s1, 0), s2);
       +        return s1;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrchr.c b/src/lib9/utf/runestrchr.c
       t@@ -0,0 +1,35 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrchr(Rune *s, Rune c)
       +{
       +        Rune c0 = c;
       +        Rune c1;
       +
       +        if(c == 0) {
       +                while(*s++)
       +                        ;
       +                return s-1;
       +        }
       +
       +        while(c1 = *s++)
       +                if(c1 == c0)
       +                        return s-1;
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrcmp.c b/src/lib9/utf/runestrcmp.c
       t@@ -0,0 +1,35 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +int
       +runestrcmp(Rune *s1, Rune *s2)
       +{
       +        Rune c1, c2;
       +
       +        for(;;) {
       +                c1 = *s1++;
       +                c2 = *s2++;
       +                if(c1 != c2) {
       +                        if(c1 > c2)
       +                                return 1;
       +                        return -1;
       +                }
       +                if(c1 == 0)
       +                        return 0;
       +        }
       +}
 (DIR) diff --git a/src/lib9/utf/runestrcpy.c b/src/lib9/utf/runestrcpy.c
       t@@ -0,0 +1,28 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrcpy(Rune *s1, Rune *s2)
       +{
       +        Rune *os1;
       +
       +        os1 = s1;
       +        while(*s1++ = *s2++)
       +                ;
       +        return os1;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrdup.c b/src/lib9/utf/runestrdup.c
       t@@ -0,0 +1,30 @@
       +/*
       + * 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 <stdlib.h>
       +#include "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrdup(Rune *s) 
       +{  
       +        Rune *ns;
       +
       +        ns = malloc(sizeof(Rune)*(runestrlen(s) + 1));
       +        if(ns == 0)
       +                return 0;
       +
       +        return runestrcpy(ns, s);
       +}
 (DIR) diff --git a/src/lib9/utf/runestrecpy.c b/src/lib9/utf/runestrecpy.c
       t@@ -0,0 +1,32 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrecpy(Rune *s1, Rune *es1, Rune *s2)
       +{
       +        if(s1 >= es1)
       +                return s1;
       +
       +        while(*s1++ = *s2++){
       +                if(s1 == es1){
       +                        *--s1 = '\0';
       +                        break;
       +                }
       +        }
       +        return s1;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrlen.c b/src/lib9/utf/runestrlen.c
       t@@ -0,0 +1,24 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +long
       +runestrlen(Rune *s)
       +{
       +
       +        return runestrchr(s, 0) - s;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrncat.c b/src/lib9/utf/runestrncat.c
       t@@ -0,0 +1,32 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrncat(Rune *s1, Rune *s2, long n)
       +{
       +        Rune *os1;
       +
       +        os1 = s1;
       +        s1 = runestrchr(s1, 0);
       +        while(*s1++ = *s2++)
       +                if(--n < 0) {
       +                        s1[-1] = 0;
       +                        break;
       +                }
       +        return os1;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrncmp.c b/src/lib9/utf/runestrncmp.c
       t@@ -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 "utf.h"
       +#include "utfdef.h"
       +
       +int
       +runestrncmp(Rune *s1, Rune *s2, long n)
       +{
       +        Rune c1, c2;
       +
       +        while(n > 0) {
       +                c1 = *s1++;
       +                c2 = *s2++;
       +                n--;
       +                if(c1 != c2) {
       +                        if(c1 > c2)
       +                                return 1;
       +                        return -1;
       +                }
       +                if(c1 == 0)
       +                        break;
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrncpy.c b/src/lib9/utf/runestrncpy.c
       t@@ -0,0 +1,33 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrncpy(Rune *s1, Rune *s2, long n)
       +{
       +        int i;
       +        Rune *os1;
       +
       +        os1 = s1;
       +        for(i = 0; i < n; i++)
       +                if((*s1++ = *s2++) == 0) {
       +                        while(++i < n)
       +                                *s1++ = 0;
       +                        return os1;
       +                }
       +        return os1;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrrchr.c b/src/lib9/utf/runestrrchr.c
       t@@ -0,0 +1,30 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.h"
       +
       +Rune*
       +runestrrchr(Rune *s, Rune c)
       +{
       +        Rune *r;
       +
       +        if(c == 0)
       +                return runestrchr(s, 0);
       +        r = 0;
       +        while(s = runestrchr(s, c))
       +                r = s++;
       +        return r;
       +}
 (DIR) diff --git a/src/lib9/utf/runestrstr.c b/src/lib9/utf/runestrstr.c
       t@@ -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 "utf.h"
       +#include "utfdef.h"
       +
       +/*
       + * Return pointer to first occurrence of s2 in s1,
       + * 0 if none
       + */
       +Rune*
       +runestrstr(Rune *s1, Rune *s2)
       +{
       +        Rune *p, *pa, *pb;
       +        int c0, c;
       +
       +        c0 = *s2;
       +        if(c0 == 0)
       +                return s1;
       +        s2++;
       +        for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) {
       +                pa = p;
       +                for(pb=s2;; pb++) {
       +                        c = *pb;
       +                        if(c == 0)
       +                                return p;
       +                        if(c != *++pa)
       +                                break;
       +                }
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
       t@@ -0,0 +1,1152 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.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;
       +}
 (DIR) diff --git a/src/lib9/utf/utfdef.h b/src/lib9/utf/utfdef.h
       t@@ -0,0 +1,14 @@
       +#define uchar _utfuchar
       +#define ushort _utfushort
       +#define uint _utfuint
       +#define ulong _utfulong
       +#define vlong _utfvlong
       +#define uvlong _utfuvlong
       +
       +typedef unsigned char                uchar;
       +typedef unsigned short                ushort;
       +typedef unsigned int                uint;
       +typedef unsigned long                ulong;
       +
       +#define nelem(x) (sizeof(x)/sizeof((x)[0]))
       +#define nil ((void*)0)
 (DIR) diff --git a/src/lib9/utf/utfecpy.c b/src/lib9/utf/utfecpy.c
       t@@ -0,0 +1,36 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.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;
       +}
 (DIR) diff --git a/src/lib9/utf/utflen.c b/src/lib9/utf/utflen.c
       t@@ -0,0 +1,38 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.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++;
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/utf/utfnlen.c b/src/lib9/utf/utfnlen.c
       t@@ -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 "utf.h"
       +#include "utfdef.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;
       +}
 (DIR) diff --git a/src/lib9/utf/utfrrune.c b/src/lib9/utf/utfrrune.c
       t@@ -0,0 +1,46 @@
       +/*
       + * 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 "utf.h"
       +#include "utfdef.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;
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/utf/utfrune.c b/src/lib9/utf/utfrune.c
       t@@ -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 "utf.h"
       +#include "utfdef.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;
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/lib9/utf/utfutf.c b/src/lib9/utf/utfutf.c
       t@@ -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 "utf.h"
       +#include "utfdef.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;
       +}