diff options
Diffstat (limited to 'lib9')
91 files changed, 5424 insertions, 0 deletions
diff --git a/lib9/NOTICE b/lib9/NOTICE new file mode 100644 index 00000000..d2099067 --- /dev/null +++ b/lib9/NOTICE @@ -0,0 +1,29 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. + Revisions Copyright © 2000-2006 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/lib9/argv0.c b/lib9/argv0.c new file mode 100644 index 00000000..10eb75cf --- /dev/null +++ b/lib9/argv0.c @@ -0,0 +1 @@ +char* argv0 = 0; diff --git a/lib9/charstod.c b/lib9/charstod.c new file mode 100644 index 00000000..53140695 --- /dev/null +++ b/lib9/charstod.c @@ -0,0 +1,68 @@ +#include "lib9.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 +charstod(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 = pow10(exp); + if(eneg) + num /= dem; + else + num *= dem; + if(neg) + return -num; + return num; +} diff --git a/lib9/cistrcmp.c b/lib9/cistrcmp.c new file mode 100644 index 00000000..fc7d84e4 --- /dev/null +++ b/lib9/cistrcmp.c @@ -0,0 +1,25 @@ +#include "lib9.h" + +int +cistrcmp(char *s1, char *s2) +{ + int c1, c2; + + while(*s1){ + c1 = *(uchar*)s1++; + c2 = *(uchar*)s2++; + + if(c1 == c2) + continue; + + if(c1 >= 'A' && c1 <= 'Z') + c1 -= 'A' - 'a'; + + if(c2 >= 'A' && c2 <= 'Z') + c2 -= 'A' - 'a'; + + if(c1 != c2) + return c1 - c2; + } + return -*s2; +} diff --git a/lib9/cistrncmp.c b/lib9/cistrncmp.c new file mode 100644 index 00000000..1d55d71b --- /dev/null +++ b/lib9/cistrncmp.c @@ -0,0 +1,27 @@ +#include "lib9.h" + +int +cistrncmp(char *s1, char *s2, int n) +{ + int c1, c2; + + while(*s1 && n-- > 0){ + c1 = *(uchar*)s1++; + c2 = *(uchar*)s2++; + + if(c1 == c2) + continue; + + if(c1 >= 'A' && c1 <= 'Z') + c1 -= 'A' - 'a'; + + if(c2 >= 'A' && c2 <= 'Z') + c2 -= 'A' - 'a'; + + if(c1 != c2) + return c1 - c2; + } + if(n <= 0) + return 0; + return -*s2; +} diff --git a/lib9/cistrstr.c b/lib9/cistrstr.c new file mode 100644 index 00000000..20d3205d --- /dev/null +++ b/lib9/cistrstr.c @@ -0,0 +1,22 @@ +#include "lib9.h" + +char* +cistrstr(char *s, char *sub) +{ + int c, csub, n; + + csub = *sub; + if(csub == '\0') + return s; + if(csub >= 'A' && csub <= 'Z') + csub -= 'A' - 'a'; + sub++; + n = strlen(sub); + for(; c = *s; s++){ + if(c >= 'A' && c <= 'Z') + c -= 'A' - 'a'; + if(c == csub && cistrncmp(s+1, sub, n) == 0) + return s; + } + return nil; +} diff --git a/lib9/cleanname.c b/lib9/cleanname.c new file mode 100644 index 00000000..baf11557 --- /dev/null +++ b/lib9/cleanname.c @@ -0,0 +1,51 @@ +#include <lib9.h> + +/* + * In place, rewrite name to compress multiple /, eliminate ., and process .. + */ +#define SEP(x) ((x)=='/' || (x) == 0) +char* +cleanname(char *name) +{ + char *p, *q, *dotdot; + int rooted; + + rooted = name[0] == '/'; + + /* + * invariants: + * p points at beginning of path element we're considering. + * q points just past the last path element we wrote (no slash). + * dotdot points just past the point where .. cannot backtrack + * any further (no slash). + */ + p = q = dotdot = name+rooted; + while(*p) { + if(p[0] == '/') /* null element */ + p++; + else if(p[0] == '.' && SEP(p[1])) + p += 1; /* don't count the separator in case it is nul */ + else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { + p += 2; + if(q > dotdot) { /* can backtrack */ + while(--q > dotdot && *q != '/') + ; + } else if(!rooted) { /* /.. is / but ./../ is .. */ + if(q != name) + *q++ = '/'; + *q++ = '.'; + *q++ = '.'; + dotdot = q; + } + } else { /* real path element */ + if(q != name+rooted) + *q++ = '/'; + while((*q = *p) != '/' && *q != 0) + p++, q++; + } + } + if(q == name) /* empty string is really ``.'' */ + *q++ = '.'; + *q = '\0'; + return name; +} diff --git a/lib9/convD2M.c b/lib9/convD2M.c new file mode 100644 index 00000000..29f0cd55 --- /dev/null +++ b/lib9/convD2M.c @@ -0,0 +1,94 @@ +#include "lib9.h" +#include "fcall.h" + +uint +sizeD2M(Dir *d) +{ + char *sv[4]; + int i, ns; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++) + if(sv[i]) + ns += strlen(sv[i]); + + return STATFIXLEN + ns; +} + +uint +convD2M(Dir *d, uchar *buf, uint nbuf) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns, nsv[4], ss; + + if(nbuf < BIT16SZ) + return 0; + + p = buf; + ebuf = buf + nbuf; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++){ + if(sv[i]) + nsv[i] = strlen(sv[i]); + else + nsv[i] = 0; + ns += nsv[i]; + } + + ss = STATFIXLEN + ns; + + /* set size befor erroring, so user can know how much is needed */ + /* note that length excludes count field itself */ + PBIT16(p, ss-BIT16SZ); + p += BIT16SZ; + + if(ss > nbuf) + return BIT16SZ; + + PBIT16(p, d->type); + p += BIT16SZ; + PBIT32(p, d->dev); + p += BIT32SZ; + PBIT8(p, d->qid.type); + p += BIT8SZ; + PBIT32(p, d->qid.vers); + p += BIT32SZ; + PBIT64(p, d->qid.path); + p += BIT64SZ; + PBIT32(p, d->mode); + p += BIT32SZ; + PBIT32(p, d->atime); + p += BIT32SZ; + PBIT32(p, d->mtime); + p += BIT32SZ; + PBIT64(p, d->length); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + ns = nsv[i]; + if(p + ns + BIT16SZ > ebuf) + return 0; + PBIT16(p, ns); + p += BIT16SZ; + if(ns) + memmove(p, sv[i], ns); + p += ns; + } + + if(ss != p - buf) + return 0; + + return p - buf; +} diff --git a/lib9/convM2D.c b/lib9/convM2D.c new file mode 100644 index 00000000..156bd763 --- /dev/null +++ b/lib9/convM2D.c @@ -0,0 +1,93 @@ +#include "lib9.h" +#include "fcall.h" + +int +statcheck(uchar *buf, uint nbuf) +{ + uchar *ebuf; + int i; + + ebuf = buf + nbuf; + + if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) + return -1; + + buf += STATFIXLEN - 4 * BIT16SZ; + + for(i = 0; i < 4; i++){ + if(buf + BIT16SZ > ebuf) + return -1; + buf += BIT16SZ + GBIT16(buf); + } + + if(buf != ebuf) + return -1; + + return 0; +} + +static char nullstring[] = ""; + +uint +convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns; + + if(nbuf < STATFIXLEN) + return 0; + + p = buf; + ebuf = buf + nbuf; + + p += BIT16SZ; /* ignore size */ + d->type = GBIT16(p); + p += BIT16SZ; + d->dev = GBIT32(p); + p += BIT32SZ; + d->qid.type = GBIT8(p); + p += BIT8SZ; + d->qid.vers = GBIT32(p); + p += BIT32SZ; + d->qid.path = GBIT64(p); + p += BIT64SZ; + d->mode = GBIT32(p); + p += BIT32SZ; + d->atime = GBIT32(p); + p += BIT32SZ; + d->mtime = GBIT32(p); + p += BIT32SZ; + d->length = GBIT64(p); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + if(p + BIT16SZ > ebuf) + return 0; + ns = GBIT16(p); + p += BIT16SZ; + if(p + ns > ebuf) + return 0; + if(strs){ + sv[i] = strs; + memmove(strs, p, ns); + strs += ns; + *strs++ = '\0'; + } + p += ns; + } + + if(strs){ + d->name = sv[0]; + d->uid = sv[1]; + d->gid = sv[2]; + d->muid = sv[3]; + }else{ + d->name = nullstring; + d->uid = nullstring; + d->gid = nullstring; + d->muid = nullstring; + } + + return p - buf; +} diff --git a/lib9/convM2S.c b/lib9/convM2S.c new file mode 100644 index 00000000..443d1957 --- /dev/null +++ b/lib9/convM2S.c @@ -0,0 +1,314 @@ +#include "lib9.h" +#include "fcall.h" + +static +uchar* +gstring(uchar *p, uchar *ep, char **s) +{ + uint n; + + if(p+BIT16SZ > ep) + return nil; + n = GBIT16(p); + p += BIT16SZ - 1; + if(p+n+1 > ep) + return nil; + /* move it down, on top of count, to make room for '\0' */ + memmove(p, p + 1, n); + p[n] = '\0'; + *s = (char*)p; + p += n+1; + return p; +} + +static +uchar* +gqid(uchar *p, uchar *ep, Qid *q) +{ + if(p+QIDSZ > ep) + return nil; + q->type = GBIT8(p); + p += BIT8SZ; + q->vers = GBIT32(p); + p += BIT32SZ; + q->path = GBIT64(p); + p += BIT64SZ; + return p; +} + +/* + * no syntactic checks. + * three causes for error: + * 1. message size field is incorrect + * 2. input buffer too short for its own data (counts too long, etc.) + * 3. too many names or qids + * gqid() and gstring() return nil if they would reach beyond buffer. + * main switch statement checks range and also can fall through + * to test at end of routine. + */ +uint +convM2S(uchar *ap, uint nap, Fcall *f) +{ + uchar *p, *ep; + uint i, size; + + p = ap; + ep = p + nap; + + if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) + return 0; + size = GBIT32(p); + p += BIT32SZ; + + if(size < BIT32SZ+BIT8SZ+BIT16SZ) + return 0; + + f->type = GBIT8(p); + p += BIT8SZ; + f->tag = GBIT16(p); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Tflush: + if(p+BIT16SZ > ep) + return 0; + f->oldtag = GBIT16(p); + p += BIT16SZ; + break; + + case Tauth: + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Tattach: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Twalk: + if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->newfid = GBIT32(p); + p += BIT32SZ; + f->nwname = GBIT16(p); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; i<f->nwname; i++){ + p = gstring(p, ep, &f->wname[i]); + if(p == nil) + break; + } + break; + + case Topen: + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tcreate: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->name); + if(p == nil) + break; + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->perm = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tread: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Twrite: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Tclunk: + case Tremove: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Tstat: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Twstat: + if(p+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + +/* + */ + case Rversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Rerror: + p = gstring(p, ep, &f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = gqid(p, ep, &f->aqid); + if(p == nil) + break; + break; + + case Rattach: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + break; + + case Rwalk: + if(p+BIT16SZ > ep) + return 0; + f->nwqid = GBIT16(p); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; i<f->nwqid; i++){ + p = gqid(p, ep, &f->wqid[i]); + if(p == nil) + break; + } + break; + + case Ropen: + case Rcreate: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + if(p+BIT32SZ > ep) + return 0; + f->iounit = GBIT32(p); + p += BIT32SZ; + break; + + case Rread: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Rwrite: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Rclunk: + case Rremove: + break; + + case Rstat: + if(p+BIT16SZ > ep) + return 0; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + + case Rwstat: + break; + } + + if(p==nil || p>ep) + return 0; + if(ap+size == p) + return size; + return 0; +} diff --git a/lib9/convS2M.c b/lib9/convS2M.c new file mode 100644 index 00000000..7035373f --- /dev/null +++ b/lib9/convS2M.c @@ -0,0 +1,385 @@ +#include "lib9.h" +#include "fcall.h" + +static +uchar* +pstring(uchar *p, char *s) +{ + uint n; + + if(s == nil){ + PBIT16(p, 0); + p += BIT16SZ; + return p; + } + + n = strlen(s); + PBIT16(p, n); + p += BIT16SZ; + memmove(p, s, n); + p += n; + return p; +} + +static +uchar* +pqid(uchar *p, Qid *q) +{ + PBIT8(p, q->type); + p += BIT8SZ; + PBIT32(p, q->vers); + p += BIT32SZ; + PBIT64(p, q->path); + p += BIT64SZ; + return p; +} + +static +uint +stringsz(char *s) +{ + if(s == nil) + return BIT16SZ; + + return BIT16SZ+strlen(s); +} + +uint +sizeS2M(Fcall *f) +{ + uint n; + int i; + + n = 0; + n += BIT32SZ; /* size */ + n += BIT8SZ; /* type */ + n += BIT16SZ; /* tag */ + + switch(f->type) + { + default: + return 0; + + case Tversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Tflush: + n += BIT16SZ; + break; + + case Tauth: + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Tattach: + n += BIT32SZ; + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Twalk: + n += BIT32SZ; + n += BIT32SZ; + n += BIT16SZ; + for(i=0; i<f->nwname; i++) + n += stringsz(f->wname[i]); + break; + + case Topen: + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tcreate: + n += BIT32SZ; + n += stringsz(f->name); + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tread: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + break; + + case Twrite: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + n += f->count; + break; + + case Tclunk: + case Tremove: + n += BIT32SZ; + break; + + case Tstat: + n += BIT32SZ; + break; + + case Twstat: + n += BIT32SZ; + n += BIT16SZ; + n += f->nstat; + break; +/* + */ + + case Rversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Rerror: + n += stringsz(f->ename); + break; + + case Rflush: + break; + + case Rauth: + n += QIDSZ; + break; + + case Rattach: + n += QIDSZ; + break; + + case Rwalk: + n += BIT16SZ; + n += f->nwqid*QIDSZ; + break; + + case Ropen: + case Rcreate: + n += QIDSZ; + n += BIT32SZ; + break; + + case Rread: + n += BIT32SZ; + n += f->count; + break; + + case Rwrite: + n += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + n += BIT16SZ; + n += f->nstat; + break; + + case Rwstat: + break; + } + return n; +} + +uint +convS2M(Fcall *f, uchar *ap, uint nap) +{ + uchar *p; + uint i, size; + + size = sizeS2M(f); + if(size == 0) + return 0; + if(size > nap) + return 0; + + p = (uchar*)ap; + + PBIT32(p, size); + p += BIT32SZ; + PBIT8(p, f->type); + p += BIT8SZ; + PBIT16(p, f->tag); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Tflush: + PBIT16(p, f->oldtag); + p += BIT16SZ; + break; + + case Tauth: + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Tattach: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Twalk: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->newfid); + p += BIT32SZ; + PBIT16(p, f->nwname); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; i<f->nwname; i++) + p = pstring(p, f->wname[i]); + break; + + case Topen: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tcreate: + PBIT32(p, f->fid); + p += BIT32SZ; + p = pstring(p, f->name); + PBIT32(p, f->perm); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tread: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Twrite: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Tclunk: + case Tremove: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Tstat: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Twstat: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; +/* + */ + + case Rversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Rerror: + p = pstring(p, f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = pqid(p, &f->aqid); + break; + + case Rattach: + p = pqid(p, &f->qid); + break; + + case Rwalk: + PBIT16(p, f->nwqid); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; i<f->nwqid; i++) + p = pqid(p, &f->wqid[i]); + break; + + case Ropen: + case Rcreate: + p = pqid(p, &f->qid); + PBIT32(p, f->iounit); + p += BIT32SZ; + break; + + case Rread: + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Rwrite: + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; + + case Rwstat: + break; + } + if(size != p-ap) + return 0; + return size; +} diff --git a/lib9/create.c b/lib9/create.c new file mode 100644 index 00000000..de624f61 --- /dev/null +++ b/lib9/create.c @@ -0,0 +1,32 @@ +#include "lib9.h" +#include <sys/types.h> +#include <fcntl.h> + +int +create(char *f, int mode, int perm) +{ + int m; + + m = 0; + switch(mode & 3){ + case OREAD: + case OEXEC: + m = O_RDONLY; + break; + case OWRITE: + m = O_WRONLY; + break; + case ORDWR: + m = O_RDWR; + break; + } + m |= O_CREAT|O_TRUNC; + + if(perm & DMDIR){ + if(mkdir(f, perm&0777) < 0) + return -1; + perm &= ~DMDIR; + m &= 3; + } + return open(f, m, perm); +} diff --git a/lib9/dirstat-Nt.c b/lib9/dirstat-Nt.c new file mode 100644 index 00000000..84db4bda --- /dev/null +++ b/lib9/dirstat-Nt.c @@ -0,0 +1,64 @@ +#include "lib9.h" +#include <sys/types.h> +#include <sys/stat.h> + +#define ISTYPE(s, t) (((s)->st_mode&S_IFMT) == t) + +static char nullstring[] = ""; +static char Enovmem[] = "out of memory"; + +static Dir* +statconv(struct stat *s, char *name) +{ + Dir *dir; + +#ifdef NO + extern char* GetNameFromID(int); + + uid = GetNameFromID(s->st_uid), NAMELEN); + gid = GetNameFromID(s->st_gid), NAMELEN); +#endif + dir = malloc(sizeof(Dir)); + if(dir == nil){ + werrstr(Enovmem); + return nil; + } + dir->name = name; + dir->uid = dir->gid = dir->muid = nullstring; + dir->qid.type = ISTYPE(s, _S_IFDIR)? QTDIR: QTFILE; + dir->qid.path = s->st_ino; + dir->qid.vers = s->st_mtime; + dir->mode = (dir->qid.type<<24)|(s->st_mode&0777); + dir->atime = s->st_atime; + dir->mtime = s->st_mtime; + dir->length = s->st_size; + dir->dev = s->st_dev; + dir->type = ISTYPE(s, _S_IFIFO)? '|': 'M'; + return dir; +} + +Dir* +dirfstat(int fd) +{ + struct stat sbuf; + + if(fstat(fd, &sbuf) < 0) + return nil; + return statconv(&sbuf, nullstring); +} + +Dir* +dirstat(char *f) +{ + struct stat sbuf; + char *p; + + if(stat(f, &sbuf) < 0) + return nil; + p = strrchr(f, '/'); + if(p) + p++; + else + p = nullstring; + return statconv(&sbuf, p); +} diff --git a/lib9/dirstat-posix.c b/lib9/dirstat-posix.c new file mode 100644 index 00000000..8925b6da --- /dev/null +++ b/lib9/dirstat-posix.c @@ -0,0 +1,79 @@ +#include "lib9.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> +#include <grp.h> + +static char nullstring[] = ""; +static char Enovmem[] = "out of memory"; + +static Dir* +statconv(struct stat *s, char *name) +{ + struct passwd *p; + struct group *g; + Dir *dir; + int str; + char *n; + + str = 0; + p = getpwuid(s->st_uid); + if(p) + str += strlen(p->pw_name)+1; + g = getgrgid(s->st_gid); + if(g) + str += strlen(g->gr_name)+1; + dir = malloc(sizeof(Dir)+str); + if(dir == nil){ + werrstr(Enovmem); + return nil; + } + n = (char*)dir+sizeof(Dir); + dir->name = name; + dir->uid = dir->gid = dir->muid = nullstring; + if(p){ + dir->uid = n; + strcpy(n, p->pw_name); + n += strlen(p->pw_name)+1; + } + if(g){ + dir->gid = n; + strcpy(n, g->gr_name); + } + dir->qid.type = S_ISDIR(s->st_mode)? QTDIR: QTFILE; + dir->qid.path = s->st_ino; + dir->qid.vers = s->st_mtime; + dir->mode = (dir->qid.type<<24)|(s->st_mode&0777); + dir->atime = s->st_atime; + dir->mtime = s->st_mtime; + dir->length = s->st_size; + dir->dev = s->st_dev; + dir->type = S_ISFIFO(s->st_mode)? '|': 'M'; + return dir; +} + +Dir* +dirfstat(int fd) +{ + struct stat sbuf; + + if(fstat(fd, &sbuf) < 0) + return nil; + return statconv(&sbuf, nullstring); +} + +Dir* +dirstat(char *f) +{ + struct stat sbuf; + char *p; + + if(stat(f, &sbuf) < 0) + return nil; + p = strrchr(f, '/'); + if(p) + p++; + else + p = nullstring; + return statconv(&sbuf, p); +} diff --git a/lib9/dirwstat.c b/lib9/dirwstat.c new file mode 100644 index 00000000..76587b9f --- /dev/null +++ b/lib9/dirwstat.c @@ -0,0 +1,15 @@ +#include "lib9.h" +#include <sys/types.h> +#include <sys/stat.h> + +int +dirfwstat(int fd, Dir *d) +{ + return -1; +} + +int +dirwstat(char *name, Dir *d) +{ + return -1; +} diff --git a/lib9/dofmt.c b/lib9/dofmt.c new file mode 100644 index 00000000..0f47c85d --- /dev/null +++ b/lib9/dofmt.c @@ -0,0 +1,532 @@ +/* + * 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 "lib9.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 = f->to; + rs = 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 = f->to; + s = 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 = _fmtflush(f, t, n); + if(t != nil) + s = 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 = _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 = f->to; + s = 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 = f->to; + s = 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, void *vm, int n, int sz) +{ + Rune *rt, *rs, r; + char *t, *s, *m, *me; + ulong fl; + int nc, w; + + m = 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 = f->to; + rs = 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 = f->to; + s = 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, void *vm, int n) +{ + Rune r, *m, *me, *rt, *rs; + char *t, *s; + ulong fl; + int w; + + m = 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 = f->to; + rs = 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 = f->to; + s = 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, x, 1, 1); +} + +/* fmt out one rune */ +int +_runefmt(Fmt *f) +{ + Rune x[1]; + + x[0] = va_arg(f->args, int); + return _fmtrcpy(f, 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, 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; + 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': + 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; + } + } + 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){ + *p-- = '0'; + n = 1; + } + 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)){ + 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': + 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, x, 3, 3); + return 0; +} diff --git a/lib9/dorfmt.c b/lib9/dorfmt.c new file mode 100644 index 00000000..645973a8 --- /dev/null +++ b/lib9/dorfmt.c @@ -0,0 +1,58 @@ +/* + * 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 "lib9.h" +#include "fmtdef.h" + +/* format the output into f->to and return the number of characters fmted */ + +int +dorfmt(Fmt *f, 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 */ +} diff --git a/lib9/errfmt.c b/lib9/errfmt.c new file mode 100644 index 00000000..7ea2ad18 --- /dev/null +++ b/lib9/errfmt.c @@ -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 "lib9.h" +#include "fmtdef.h" + +int +errfmt(Fmt *f) +{ + char buf[ERRMAX]; + + rerrstr(buf, sizeof buf); + return _fmtcpy(f, buf, utflen(buf), strlen(buf)); +} diff --git a/lib9/errstr-Nt.c b/lib9/errstr-Nt.c new file mode 100644 index 00000000..53c35323 --- /dev/null +++ b/lib9/errstr-Nt.c @@ -0,0 +1,65 @@ +#include "lib9.h" +#include <Windows.h> + +static char errstring[ERRMAX]; + +enum +{ + Magic = 0xffffff +}; + +static void +winerror(int e, char *buf, uint nerr) +{ + int r; + char buf2[ERRMAX], *p, *q; + + r = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + 0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf2, sizeof(buf2), 0); + + if(r == 0) + snprint(buf2, ERRMAX, "windows error %d", e); + + q = buf2; + for(p = buf2; *p; p++) { + if(*p == '\r') + continue; + if(*p == '\n') + *q++ = ' '; + else + *q++ = *p; + } + *q = '\0'; + utfecpy(buf, buf+nerr, buf2); +} + +void +werrstr(char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + vseprint(errstring, errstring+sizeof(errstring), fmt, arg); + va_end(arg); + SetLastError(Magic); +} + +int +errstr(char *buf, uint nerr) +{ + DWORD le; + + le = GetLastError(); + if(le == Magic) + utfecpy(buf, buf+nerr, errstring); + else + winerror(le, buf, nerr); + return 1; +} + +void +oserrstr(char *buf, uint nerr) +{ + winerror(GetLastError(), buf, nerr); +} diff --git a/lib9/errstr-Plan9.c b/lib9/errstr-Plan9.c new file mode 100644 index 00000000..56e867c4 --- /dev/null +++ b/lib9/errstr-Plan9.c @@ -0,0 +1,8 @@ +#include "lib9.h" + +void +oserrstr(char *buf, uint nerr) +{ + *buf = 0; + errstr(buf, nerr); +} diff --git a/lib9/errstr-posix.c b/lib9/errstr-posix.c new file mode 100644 index 00000000..eacc7754 --- /dev/null +++ b/lib9/errstr-posix.c @@ -0,0 +1,37 @@ +#include "lib9.h" + +#include <errno.h> + +static char errstring[ERRMAX]; + +enum +{ + Magic = 0xffffff +}; + +void +werrstr(char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + vseprint(errstring, errstring+sizeof(errstring), fmt, arg); + va_end(arg); + errno = Magic; +} + +void +oserrstr(char *buf, uint nerr) +{ + utfecpy(buf, buf+nerr, strerror(errno)); +} + +int +errstr(char *buf, uint nerr) +{ + if(errno == Magic) + utfecpy(buf, buf+nerr, errstring); + else + oserrstr(buf, nerr); + return 1; +} diff --git a/lib9/exits.c b/lib9/exits.c new file mode 100644 index 00000000..2bedbf09 --- /dev/null +++ b/lib9/exits.c @@ -0,0 +1,17 @@ +#include "lib9.h" + +void +exits(char *s) +{ + if(s == 0 || *s == 0) + exit(0); + exit(1); +} + +void +_exits(char *s) +{ + if(s == 0 || *s == 0) + _exit(0); + _exit(1); +} diff --git a/lib9/fcallfmt.c b/lib9/fcallfmt.c new file mode 100644 index 00000000..e35872ef --- /dev/null +++ b/lib9/fcallfmt.c @@ -0,0 +1,246 @@ +/* + * 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 <lib9.h> +#include "fcall.h" + +static uint dumpsome(char*, char*, char*, long); +static void fdirconv(char*, char*, Dir*); +static char *qidtype(char*, uchar); + +#define QIDFMT "(%.16llux %lud %s)" + +int +fcallfmt(Fmt *fmt) +{ + Fcall *f; + int fid, type, tag, i; + char buf[512], tmp[200]; + char *p, *e; + Dir *d; + Qid *q; + + e = buf+sizeof(buf); + f = va_arg(fmt->args, Fcall*); + type = f->type; + fid = f->fid; + tag = f->tag; + switch(type){ + case Tversion: /* 100 */ + seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Rversion: + seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Tauth: /* 102 */ + seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag, + f->afid, f->uname, f->aname); + break; + case Rauth: + seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag, + f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type)); + break; + case Tattach: /* 104 */ + seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag, + fid, f->afid, f->uname, f->aname); + break; + case Rattach: + seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type)); + break; + case Rerror: /* 107; 106 (Terror) illegal */ + seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename); + break; + case Tflush: /* 108 */ + seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag); + break; + case Rflush: + seprint(buf, e, "Rflush tag %ud", tag); + break; + case Twalk: /* 110 */ + p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname); + if(f->nwname <= MAXWELEM) + for(i=0; i<f->nwname; i++) + p = seprint(p, e, "%d:%s ", i, f->wname[i]); + break; + case Rwalk: + p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid); + if(f->nwqid <= MAXWELEM) + for(i=0; i<f->nwqid; i++){ + q = &f->wqid[i]; + p = seprint(p, e, "%d:" QIDFMT " ", i, + q->path, q->vers, qidtype(tmp, q->type)); + } + break; + case Topen: /* 112 */ + seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode); + break; + case Ropen: + seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tcreate: /* 114 */ + seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode); + break; + case Rcreate: + seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tread: /* 116 */ + seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud", + tag, fid, f->offset, f->count); + break; + case Rread: + p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Twrite: /* 118 */ + p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ", + tag, fid, f->offset, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Rwrite: + seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count); + break; + case Tclunk: /* 120 */ + seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid); + break; + case Rclunk: + seprint(buf, e, "Rclunk tag %ud", tag); + break; + case Tremove: /* 122 */ + seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid); + break; + case Rremove: + seprint(buf, e, "Rremove tag %ud", tag); + break; + case Tstat: /* 124 */ + seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid); + break; + case Rstat: + p = seprint(buf, e, "Rstat tag %ud ", tag); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Twstat: /* 126 */ + p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Rwstat: + seprint(buf, e, "Rwstat tag %ud", tag); + break; + default: + seprint(buf, e, "unknown type %d", type); + } + return fmtstrcpy(fmt, buf); +} + +static char* +qidtype(char *s, uchar t) +{ + char *p; + + p = s; + if(t & QTDIR) + *p++ = 'd'; + if(t & QTAPPEND) + *p++ = 'a'; + if(t & QTEXCL) + *p++ = 'l'; + if(t & QTAUTH) + *p++ = 'A'; + *p = '\0'; + return s; +} + +int +dirfmt(Fmt *fmt) +{ + char buf[160]; + + fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*)); + return fmtstrcpy(fmt, buf); +} + +static void +fdirconv(char *buf, char *e, Dir *d) +{ + char tmp[16]; + + seprint(buf, e, "'%s' '%s' '%s' '%s' " + "q " QIDFMT " m %#luo " + "at %ld mt %ld l %lld " + "t %d d %d", + d->name, d->uid, d->gid, d->muid, + d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode, + d->atime, d->mtime, d->length, + d->type, d->dev); +} + +/* + * dump out count (or DUMPL, if count is bigger) bytes from + * buf to ans, as a string if they are all printable, + * else as a series of hex bytes + */ +#define DUMPL 64 + +static uint +dumpsome(char *ans, char *e, char *buf, long count) +{ + int i, printable; + char *p; + + if(buf == nil){ + seprint(ans, e, "<no data>"); + return strlen(ans); + } + printable = 1; + if(count > DUMPL) + count = DUMPL; + for(i=0; i<count && printable; i++) + if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127) + printable = 0; + p = ans; + *p++ = '\''; + if(printable){ + if(count > e-p-2) + count = e-p-2; + memmove(p, buf, count); + p += count; + }else{ + if(2*count > e-p-2) + count = (e-p-2)/2; + for(i=0; i<count; i++){ + if(i>0 && i%4==0) + *p++ = ' '; + sprint(p, "%2.2ux", buf[i]); + p += 2; + } + } + *p++ = '\''; + *p = 0; + return p - ans; +} diff --git a/lib9/fltfmt.c b/lib9/fltfmt.c new file mode 100644 index 00000000..739a4bf7 --- /dev/null +++ b/lib9/fltfmt.c @@ -0,0 +1,324 @@ +/* + * 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 "lib9.h" +#include <ctype.h> +#include "fmtdef.h" + +enum +{ + FDIGIT = 30, + FDEFLT = 6, + NSIGNIF = 17, +}; + +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 +xdtoa(Fmt *fmt, char *s2, double f) +{ + char s1[NSIGNIF+10]; + double g, h; + int e, d, i, n; + int c1, c2, c3, c4, ucase, sign, chr, prec; + + prec = FDEFLT; + if(fmt->flags & FmtPrec) + prec = fmt->prec; + if(prec > FDIGIT) + prec = FDIGIT; + if(isNaN(f)) { + strcpy(s2, "NaN"); + return; + } + if(isInf(f, 1)) { + strcpy(s2, "+Inf"); + return; + } + if(isInf(f, -1)) { + strcpy(s2, "-Inf"); + return; + } + sign = 0; + if(f < 0) { + f = -f; + sign++; + } + ucase = 0; + chr = fmt->r; + if(isupper(chr)) { + ucase = 1; + chr = tolower(chr); + } + + e = 0; + g = f; + if(g != 0) { + frexp(f, &e); + e = 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 = 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; + if(c2 >= NSIGNIF-2) { + strcpy(s2, s1); + d = e; + s1[NSIGNIF-2] = '0'; + s1[NSIGNIF-1] = '0'; + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + g = strtod(s1, nil); + if(g == f) + goto found; + if(xadd(s1, NSIGNIF-3, 1)) { + e++; + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + } + g = strtod(s1, nil); + if(g == f) + goto found; + strcpy(s1, s2); + e = d; + } + + /* + * convert back so s1 gets exact answer + */ + for(;;) { + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + g = strtod(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: + /* + * sign + */ + d = 0; + i = 0; + if(sign) + s2[d++] = '-'; + else if(fmt->flags & FmtSign) + s2[d++] = '+'; + else if(fmt->flags & FmtSpace) + s2[d++] = ' '; + + /* + * 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: + if(xadd(s1, c2, 5)) + e++; + break; + case 'g': + /* + * decide on 'e' of 'f' style convers + */ + if(xadd(s1, c2, 5)) + e++; + if(e >= -5 && e <= prec) { + c1 = -e - 1; + c4 = prec - e; + chr = 'h'; // flag for 'f' style + } + break; + case 'f': + if(xadd(s1, c2+e, 5)) + e++; + c1 = -e; + if(c1 > prec) + c1 = c2; + 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; + } + + /* + * copy digits + */ + while(c1 > 0) { + if(c1+c2+c3 == c4) + s2[d++] = '.'; + s2[d++] = '0'; + c1--; + } + while(c2 > 0) { + if(c2+c3 == c4) + s2[d++] = '.'; + s2[d++] = s1[i++]; + c2--; + } + while(c3 > 0) { + if(c3 == c4) + s2[d++] = '.'; + s2[d++] = '0'; + c3--; + } + + /* + * strip trailing '0' on g conv + */ + if(fmt->flags & FmtSharp) { + if(0 == c4) + s2[d++] = '.'; + } else + if(chr == 'g' || chr == 'h') { + for(n=d-1; n>=0; n--) + if(s2[n] != '0') + break; + for(i=n; i>=0; i--) + if(s2[i] == '.') { + d = n; + if(i != n) + d++; + break; + } + } + if(chr == 'e' || chr == 'g') { + if(ucase) + s2[d++] = 'E'; + else + s2[d++] = 'e'; + c1 = e; + if(c1 < 0) { + s2[d++] = '-'; + c1 = -c1; + } else + s2[d++] = '+'; + if(c1 >= 100) { + s2[d++] = c1/100 + '0'; + c1 = c1%100; + } + s2[d++] = c1/10 + '0'; + s2[d++] = c1%10 + '0'; + } + s2[d] = 0; +} + +int +_floatfmt(Fmt *fmt, double f) +{ + char s[FDIGIT+10]; + + xdtoa(fmt, s, f); + fmt->flags &= FmtWidth|FmtLeft; + _fmtcpy(fmt, s, strlen(s), strlen(s)); + return 0; +} + +int +_efgfmt(Fmt *f) +{ + double d; + + d = va_arg(f->args, double); + return _floatfmt(f, d); +} diff --git a/lib9/fmt.c b/lib9/fmt.c new file mode 100644 index 00000000..11aac065 --- /dev/null +++ b/lib9/fmt.c @@ -0,0 +1,188 @@ +/* + * 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 "lib9.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, + 'S', _runesfmt, + 'X', _ifmt, + 'b', _ifmt, + 'c', _charfmt, + 'd', _ifmt, + 'h', _flagfmt, + 'l', _flagfmt, + 'n', _countfmt, + 'o', _ifmt, + 'p', _ifmt, + 'r', errfmt, + 's', _strfmt, + 'u', _flagfmt, + 'x', _ifmt, + 0, nil, +}; + +int (*doquote)(int); + +static Fmts +fmtfmt(int c) +{ + Convfmt *p, *ep; + + ep = &fmtalloc.fmt[fmtalloc.nfmt]; + for(p=fmtalloc.fmt; p<ep; p++) + if(p->c == c) + return p->fmt; + + /* is this a predefined format char? */ + for(p=knownfmt; p->c; p++) + if(p->c == c){ + /* no need to lock; fmtinstall is idempotent */ + fmtinstall(p->c, p->fmt); + while(p->fmt == nil) /* loop until value is updated */ + ; + return p->fmt; + } + + return _badfmt; +} + +int +fmtinstall(int c, Fmts f) +{ + Convfmt *p, *ep; + + if(c<=0 || c>=65536) + return -1; + if(!f) + f = _badfmt; + + _fmtlock(); + + ep = &fmtalloc.fmt[fmtalloc.nfmt]; + for(p=fmtalloc.fmt; p<ep; p++) + if(p->c == c) + break; + + if(p == &fmtalloc.fmt[Maxfmt]){ + _fmtunlock(); + return -1; + } + + p->fmt = f; + if(p == ep){ /* installing a new format character */ + fmtalloc.nfmt++; + p->c = c; + } + + _fmtunlock(); + return 0; +} + +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, 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){ + i = -i; + f->flags |= FmtLeft; + } + goto numflag; + } + n = (*fmtfmt(r))(f); + if(n < 0) + return nil; + if(n == 0) + return fmt; + } +} diff --git a/lib9/fmtdef.h b/lib9/fmtdef.h new file mode 100644 index 00000000..071041cf --- /dev/null +++ b/lib9/fmtdef.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +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 _countfmt(Fmt*); +int _flagfmt(Fmt*); +int _percentfmt(Fmt*); +int _ifmt(Fmt*); +int _runefmt(Fmt*); +int _runesfmt(Fmt*); +int _strfmt(Fmt*); +int _badfmt(Fmt*); +int _fmtcpy(Fmt*, void*, int, int); +int _fmtrcpy(Fmt*, void*, int n); + +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) diff --git a/lib9/fmtfd.c b/lib9/fmtfd.c new file mode 100644 index 00000000..ea476294 --- /dev/null +++ b/lib9/fmtfd.c @@ -0,0 +1,43 @@ +/* + * 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 "lib9.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; +} diff --git a/lib9/fmtlock.c b/lib9/fmtlock.c new file mode 100644 index 00000000..66e3b724 --- /dev/null +++ b/lib9/fmtlock.c @@ -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 "lib9.h" + +void +_fmtlock(void) +{ +} + +void +_fmtunlock(void) +{ +} diff --git a/lib9/fmtprint.c b/lib9/fmtprint.c new file mode 100644 index 00000000..c93cb315 --- /dev/null +++ b/lib9/fmtprint.c @@ -0,0 +1,44 @@ +/* + * The authors of this software are Rob Pike and Ken Thompson. + * Copyright (c) 2002 by Lucent Technologies. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ +#include "lib9.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; +} + diff --git a/lib9/fmtquote.c b/lib9/fmtquote.c new file mode 100644 index 00000000..3e6338bf --- /dev/null +++ b/lib9/fmtquote.c @@ -0,0 +1,259 @@ +/* + * 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 "lib9.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'\'') || (doquote!=nil && doquote(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 = f->to; + s = f->stop; + rt = f->to; + rs = 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 = *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, "<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; +} diff --git a/lib9/fmtrune.c b/lib9/fmtrune.c new file mode 100644 index 00000000..65e620e6 --- /dev/null +++ b/lib9/fmtrune.c @@ -0,0 +1,37 @@ +/* + * The authors of this software are Rob Pike and Ken Thompson. + * Copyright (c) 2002 by Lucent Technologies. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ +#include "lib9.h" +#include "fmtdef.h" + +int +fmtrune(Fmt *f, int r) +{ + Rune *rt; + char *t; + int n; + + if(f->runes){ + rt = f->to; + FMTRCHAR(f, rt, f->stop, r); + f->to = rt; + n = 1; + }else{ + t = f->to; + FMTRUNE(f, t, f->stop, r); + n = t - (char*)f->to; + f->to = t; + } + f->nfmt += n; + return 0; +} diff --git a/lib9/fmtstr.c b/lib9/fmtstr.c new file mode 100644 index 00000000..9f94d134 --- /dev/null +++ b/lib9/fmtstr.c @@ -0,0 +1,23 @@ +/* + * 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 "lib9.h" + +char* +fmtstrflush(Fmt *f) +{ + if(f->start == nil) + return nil; + *(char*)f->to = '\0'; + return f->start; +} diff --git a/lib9/fmtvprint.c b/lib9/fmtvprint.c new file mode 100644 index 00000000..6682cd33 --- /dev/null +++ b/lib9/fmtvprint.c @@ -0,0 +1,43 @@ +/* + * 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 "lib9.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; +} + diff --git a/lib9/fprint.c b/lib9/fprint.c new file mode 100644 index 00000000..1cbb34c7 --- /dev/null +++ b/lib9/fprint.c @@ -0,0 +1,26 @@ +/* + * 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 "lib9.h" + +int +fprint(int fd, char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vfprint(fd, fmt, args); + va_end(args); + return n; +} diff --git a/lib9/getcallerpc-FreeBSD-386.S b/lib9/getcallerpc-FreeBSD-386.S new file mode 100644 index 00000000..134c2847 --- /dev/null +++ b/lib9/getcallerpc-FreeBSD-386.S @@ -0,0 +1,7 @@ + .file "getcallerpc-FreeBSD-386.S" + + .type getcallerpc,@function + .global getcallerpc +getcallerpc: + movl 4(%ebp), %eax + ret diff --git a/lib9/getcallerpc-Hp-s800.s b/lib9/getcallerpc-Hp-s800.s new file mode 100644 index 00000000..2a1f4080 --- /dev/null +++ b/lib9/getcallerpc-Hp-s800.s @@ -0,0 +1,12 @@ + .LEVEL 1.1 + + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY,SORT=24 +getcallerpc + .PROC + .CALLINFO FRAME=0,ARGS_SAVED + .ENTRY + LDI 0,%r28 + .EXIT + BV,N %r0(%r2) + .PROCEND diff --git a/lib9/getcallerpc-Irix-mips.s b/lib9/getcallerpc-Irix-mips.s new file mode 100644 index 00000000..298e1da6 --- /dev/null +++ b/lib9/getcallerpc-Irix-mips.s @@ -0,0 +1,9 @@ +#include <sys/regdef.h> +#include <sys/asm.h> + +LEAF(getcallerpc) + .set noreorder + lw v0, 28(sp) + j ra + .set reorder + END(getcallerpc) diff --git a/lib9/getcallerpc-Linux-386.S b/lib9/getcallerpc-Linux-386.S new file mode 100644 index 00000000..71b58781 --- /dev/null +++ b/lib9/getcallerpc-Linux-386.S @@ -0,0 +1,7 @@ + .file "getcallerpc-Linux-386.S" + .text + .type getcallerpc,@function + .global getcallerpc +getcallerpc: + movl 4(%ebp), %eax + ret diff --git a/lib9/getcallerpc-MacOSX-power.s b/lib9/getcallerpc-MacOSX-power.s new file mode 100644 index 00000000..d0c7c8ab --- /dev/null +++ b/lib9/getcallerpc-MacOSX-power.s @@ -0,0 +1,19 @@ +/* + File: getcallerpc-Darwin-power.s + + getcallerpc() is passed a pointer + + Plan 9 asm: + + TEXT getcallerpc(SB), $-4 + MOVW 0(R1), R3 + RETURN + + */ + +#import <architecture/ppc/asm_help.h> + +.text +LABEL(_getcallerpc) + mflr r3 + blr diff --git a/lib9/getcallerpc-Solaris-386.s b/lib9/getcallerpc-Solaris-386.s new file mode 100644 index 00000000..5d4c7053 --- /dev/null +++ b/lib9/getcallerpc-Solaris-386.s @@ -0,0 +1,8 @@ + .align 4 + .globl getcallerpc +getcallerpc: + movl 4(%ebp),%eax + ret + .align 4 + .type getcallerpc,@function + .size getcallerpc,.-getcallerpc diff --git a/lib9/getcallerpc-Solaris-sparc.s b/lib9/getcallerpc-Solaris-sparc.s new file mode 100644 index 00000000..79e18fa0 --- /dev/null +++ b/lib9/getcallerpc-Solaris-sparc.s @@ -0,0 +1,11 @@ + .section ".text", #alloc, #execinstr + .align 8 + .skip 16 + .global getcallerpc + .type getcallerpc, 2 +getcallerpc: ! ignore argument + retl + add %i7,0,%o0 + + .size getcallerpc,(.-getcallerpc) + diff --git a/lib9/getcallerpc-Unixware-386.s b/lib9/getcallerpc-Unixware-386.s new file mode 100644 index 00000000..5d4c7053 --- /dev/null +++ b/lib9/getcallerpc-Unixware-386.s @@ -0,0 +1,8 @@ + .align 4 + .globl getcallerpc +getcallerpc: + movl 4(%ebp),%eax + ret + .align 4 + .type getcallerpc,@function + .size getcallerpc,.-getcallerpc diff --git a/lib9/getfields.c b/lib9/getfields.c new file mode 100644 index 00000000..44d7417c --- /dev/null +++ b/lib9/getfields.c @@ -0,0 +1,35 @@ +#include "lib9.h" +int +getfields(char *str, char **args, int max, int mflag, char *set) +{ + Rune r; + int nr, intok, narg; + + if(max <= 0) + return 0; + + narg = 0; + args[narg] = str; + if(!mflag) + narg++; + intok = 0; + for(;; str += nr) { + nr = chartorune(&r, str); + if(r == 0) + break; + if(utfrune(set, r)) { + if(narg >= max) + break; + *str = 0; + intok = 0; + args[narg] = str + nr; + if(!mflag) + narg++; + } else { + if(!intok && mflag) + narg++; + intok = 1; + } + } + return narg; +} diff --git a/lib9/getuser-Nt.c b/lib9/getuser-Nt.c new file mode 100644 index 00000000..3d478f8a --- /dev/null +++ b/lib9/getuser-Nt.c @@ -0,0 +1,9 @@ +#include "lib9.h" + +char* +getuser(void) +{ + static char *user = 0; + user = "unknown"; + return user; +} diff --git a/lib9/getuser-posix.c b/lib9/getuser-posix.c new file mode 100644 index 00000000..018ee33c --- /dev/null +++ b/lib9/getuser-posix.c @@ -0,0 +1,22 @@ +#include "lib9.h" +#include <pwd.h> + +char* +getuser(void) +{ + struct passwd *p; + + static char *user = 0; + + if (!user) { + p = getpwuid(getuid()); + if (p && p->pw_name) { + user = malloc(strlen(p->pw_name)+1); + if (user) + strcpy(user, p->pw_name); + } + } + if(!user) + user = "unknown"; + return user; +} diff --git a/lib9/getwd-Nt.c b/lib9/getwd-Nt.c new file mode 100644 index 00000000..dcda8361 --- /dev/null +++ b/lib9/getwd-Nt.c @@ -0,0 +1,24 @@ +#include "lib9.h" +#include <windows.h> + + +char* +getwd(char *buf, int size) +{ + int n; + char *p; + + buf[0] = 0; + + n = GetCurrentDirectory(size, buf); + if(n == 0) { + /*winerror();*/ + return 0; + } + + for(p=buf; *p; p++) + if(*p == '\\') + *p = '/'; + + return buf; +} diff --git a/lib9/getwd-posix.c b/lib9/getwd-posix.c new file mode 100644 index 00000000..8554a47e --- /dev/null +++ b/lib9/getwd-posix.c @@ -0,0 +1,9 @@ +#include "lib9.h" +#undef getwd +#include <unistd.h> + +char * +infgetwd(char *buf, int size) +{ + return getcwd(buf, size); +} diff --git a/lib9/lock-Hp-s800.s b/lib9/lock-Hp-s800.s new file mode 100644 index 00000000..26b6ca47 --- /dev/null +++ b/lib9/lock-Hp-s800.s @@ -0,0 +1,38 @@ +; +; /* +; * To get lock routine, compile this into a .s, then SUBSTITUTE +; * a LOAD AND CLEAR WORD instruction for the load and store of +; * l->key. +; * +; */ +; typedef struct Lock { +; int key; +; } Lock; +; +; int +; mutexlock(Lock *l) +; { +; int key; +; +; key = l->key; +; l->key = 0; +; return key != 0; +; } + + .LEVEL 1.1 + + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY,SORT=24 +mutexlock + .PROC + .CALLINFO FRAME=0,ARGS_SAVED + .ENTRY +; SUBSTITUTED LDW 0(%r26),%r31 +; SUBSTITUTED STWS %r0,0(%r26) + LDCWS 0(%r26),%r31 ; SUBSTITUTED + COMICLR,= 0,%r31,%r28 + LDI 1,%r28 + .EXIT + BV,N %r0(%r2) + .PROCEND + .end diff --git a/lib9/lock-Irix-mips.s b/lib9/lock-Irix-mips.s new file mode 100644 index 00000000..40606e93 --- /dev/null +++ b/lib9/lock-Irix-mips.s @@ -0,0 +1,19 @@ +#include <sys/regdef.h> +#include <sys/asm.h> + +/* + * lock from r4000 book + */ +LEAF(canlock) + .set noreorder +1: + ll t0,0(a0) /* a0 is argument */ + or t1, t0, 1 + sc t1,0(a0) + beq t1,zero,1b + nop + j $31 /* lock held */ + xor v0, t0, 1 + + .set reorder + END(canlock) diff --git a/lib9/lock-MacOSX-power.s b/lib9/lock-MacOSX-power.s new file mode 100644 index 00000000..d5e15d4d --- /dev/null +++ b/lib9/lock-MacOSX-power.s @@ -0,0 +1,16 @@ +#include <architecture/ppc/asm_help.h> + +LEAF(__tas) + sync + mr r4,r3 + addi r5,0,0x1 +1: + lwarx r3,0,r4 + cmpwi r3,0x0 + bne- 2f + stwcx. r5,0,r4 + bne- 1b /* Lost reservation, try again */ +2: + sync + blr +END(__tas) diff --git a/lib9/lock-Nt-386.c b/lib9/lock-Nt-386.c new file mode 100644 index 00000000..641907ef --- /dev/null +++ b/lib9/lock-Nt-386.c @@ -0,0 +1,15 @@ +#include "lib9.h" + +ulong +_tas(ulong *la) +{ + ulong v; + + _asm { + mov eax, la + mov ebx, 1 + xchg ebx, [eax] + mov v, ebx + } + return v; +} diff --git a/lib9/lock-Solaris-386.s b/lib9/lock-Solaris-386.s new file mode 100644 index 00000000..d3f5a581 --- /dev/null +++ b/lib9/lock-Solaris-386.s @@ -0,0 +1,56 @@ + .section .bss + .align 4 +.L4_.bss: + .align 4 +Solaris_Asm_IntP: / Offset 0 + .type Solaris_Asm_IntP,@object + .size Solaris_Asm_IntP,4 + .set .,.+4 +Solaris_Asm_VoidP: / Offset 4 + .type Solaris_Asm_VoidP,@object + .size Solaris_Asm_VoidP,4 + .set .,.+4 + .section .data + .align 4 +.L2_.data: + .align 4 +.L01: .string "canlock corrupted 0x%lux\n\000" + .set .,.+0x2 + .section .text + .align 4 +.L1_.text: + + .align 4 + .align 4 + .globl canlock +canlock: + pushl %ebp + movl %esp,%ebp + pushl %esi + movl 8(%ebp),%eax + movl %eax,Solaris_Asm_IntP + movl $1, %ecx + xchg (%eax), %ecx + andl %ecx,%ecx + jne .L1 + movl $1,%esi + jmp .L2 + .align 4 +.L3: + subl %esi,%esi + jmp .L2 + .align 4 +.L1: + cmpl $1,%ecx + je .L3 + pushl %ecx + pushl $.L01 + call print + addl $8,%esp +.L2: + movl %esi,%eax + popl %esi + leave + ret + .type canlock,@function + .size canlock,.-canlock diff --git a/lib9/lock-Solaris-sparc.s b/lib9/lock-Solaris-sparc.s new file mode 100644 index 00000000..d0f9399f --- /dev/null +++ b/lib9/lock-Solaris-sparc.s @@ -0,0 +1,20 @@ + + .section ".text", #alloc, #execinstr + .align 8 + .skip 16 + .global canlock + .type canlock,2 + +canlock: + or %g0,1,%o1 + swap [%o0],%o1 ! o0 points to lock; key is first word + cmp %o1,1 + bne .gotit + nop + retl ! key was 1 + or %g0,0,%o0 +.gotit: + retl ! key was not 1 + or %g0,1,%o0 + + .size canlock,(.-canlock) diff --git a/lib9/lock-Unixware-386.s b/lib9/lock-Unixware-386.s new file mode 100644 index 00000000..efa33d02 --- /dev/null +++ b/lib9/lock-Unixware-386.s @@ -0,0 +1,56 @@ + .section .bss + .align 4 +.L4_.bss: + .align 4 +Unixware_Asm_IntP: / Offset 0 + .type Unixware_Asm_IntP,@object + .size Unixware_Asm_IntP,4 + .set .,.+4 +Unixware_Asm_VoidP: / Offset 4 + .type Unixware_Asm_VoidP,@object + .size Unixware_Asm_VoidP,4 + .set .,.+4 + .section .data + .align 4 +.L2_.data: + .align 4 +.L01: .string "canlock corrupted 0x%lux\n\000" + .set .,.+0x2 + .section .text + .align 4 +.L1_.text: + + .align 4 + .align 4 + .globl canlock +canlock: + pushl %ebp + movl %esp,%ebp + pushl %esi + movl 8(%ebp),%eax + movl %eax,Unixware_Asm_IntP + movl $1, %ecx + xchg (%eax), %ecx + andl %ecx,%ecx + jne .L1 + movl $1,%esi + jmp .L2 + .align 4 +.L3: + subl %esi,%esi + jmp .L2 + .align 4 +.L1: + cmpl $1,%ecx + je .L3 + pushl %ecx + pushl $.L01 + call print + addl $8,%esp +.L2: + movl %esi,%eax + popl %esi + leave + ret + .type canlock,@function + .size canlock,.-canlock diff --git a/lib9/lock.c b/lib9/lock.c new file mode 100644 index 00000000..48b5d8c2 --- /dev/null +++ b/lib9/lock.c @@ -0,0 +1,141 @@ +#include "dat.h" +#include "fns.h" +#include "error.h" + +void +lock(Lock *l) +{ + int i; + + if(_tas(&l->val) == 0) + return; + for(i=0; i<100; i++){ + if(_tas(&l->val) == 0) + return; + osyield(); + } + for(i=1;; i++){ + if(_tas(&l->val) == 0) + return; + osmillisleep(i*10); + if(i > 100){ + osyield(); + i = 1; + } + } +} + +int +canlock(Lock *l) +{ + return _tas(&l->val) == 0; +} + +void +unlock(Lock *l) +{ + l->val = 0; +} + +void +qlock(QLock *q) +{ + Proc *p; + + lock(&q->use); + if(!q->locked) { + q->locked = 1; + unlock(&q->use); + return; + } + p = q->tail; + if(p == 0) + q->head = up; + else + p->qnext = up; + q->tail = up; + up->qnext = 0; + unlock(&q->use); + osblock(); +} + +int +canqlock(QLock *q) +{ + if(!canlock(&q->use)) + return 0; + if(q->locked){ + unlock(&q->use); + return 0; + } + q->locked = 1; + unlock(&q->use); + return 1; +} + +void +qunlock(QLock *q) +{ + Proc *p; + + lock(&q->use); + p = q->head; + if(p) { + q->head = p->qnext; + if(q->head == 0) + q->tail = 0; + unlock(&q->use); + osready(p); + return; + } + q->locked = 0; + unlock(&q->use); +} + +void +rlock(RWlock *l) +{ + qlock(&l->x); /* wait here for writers and exclusion */ + lock(&l->l); + l->readers++; + canqlock(&l->k); /* block writers if we are the first reader */ + unlock(&l->l); + qunlock(&l->x); +} + +/* same as rlock but punts if there are any writers waiting */ +int +canrlock(RWlock *l) +{ + if (!canqlock(&l->x)) + return 0; + lock(&l->l); + l->readers++; + canqlock(&l->k); /* block writers if we are the first reader */ + unlock(&l->l); + qunlock(&l->x); + return 1; +} + +void +runlock(RWlock *l) +{ + lock(&l->l); + if(--l->readers == 0) /* last reader out allows writers */ + qunlock(&l->k); + unlock(&l->l); +} + +void +wlock(RWlock *l) +{ + qlock(&l->x); /* wait here for writers and exclusion */ + qlock(&l->k); /* wait here for last reader */ +} + +void +wunlock(RWlock *l) +{ + qunlock(&l->k); + qunlock(&l->x); +} diff --git a/lib9/mkfile b/lib9/mkfile new file mode 100644 index 00000000..32e1aa56 --- /dev/null +++ b/lib9/mkfile @@ -0,0 +1,85 @@ +<../mkconfig + +LIB=lib9.a + +# +# files used by all models +# +COMMONFILES=\ + convD2M.$O\ + convM2D.$O\ + convM2S.$O\ + convS2M.$O\ + fcallfmt.$O\ + qsort.$O\ + runestrlen.$O\ + strtoll.$O\ + rune.$O\ +# +# files used by most models. these are added to TARGFILES in some +# model-specific mkfiles included below +# +IMPORTFILES=\ + argv0.$O\ + charstod.$O\ + cistrcmp.$O\ + cistrncmp.$O\ + cistrstr.$O\ + cleanname.$O\ + create.$O\ + dirwstat.$O\ + dofmt.$O\ + dorfmt.$O\ + errfmt.$O\ + exits.$O\ + fmt.$O\ + fmtfd.$O\ + fmtlock.$O\ + fmtprint.$O\ + fmtquote.$O\ + fmtrune.$O\ + fmtstr.$O\ + fmtvprint.$O\ + fprint.$O\ + getfields.$O\ + nulldir.$O\ + pow10.$O\ + print.$O\ + readn.$O\ + rerrstr.$O\ + seek.$O\ + seprint.$O\ + smprint.$O\ + snprint.$O\ + sprint.$O\ + strdup.$O\ + strecpy.$O\ + sysfatal.$O\ + tokenize.$O\ + u16.$O\ + u32.$O\ + u64.$O\ + utflen.$O\ + utfnlen.$O\ + utfrrune.$O\ + utfrune.$O\ + utfecpy.$O\ + vfprint.$O\ + vseprint.$O\ + vsmprint.$O\ + vsnprint.$O\ + +<mkfile-$TARGMODEL + +OFILES=$COMMONFILES $TARGFILES + +HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/lib9.h\ + fmtdef.h\ + +<$ROOT/mkfiles/mksyslib-$SHELLTYPE + +convD2M.$O: $ROOT/include/fcall.h +convM2D.$O: $ROOT/include/fcall.h +convM2S.$O: $ROOT/include/fcall.h +convS2M.$O: $ROOT/include/fcall.h +fcallfmt.$O: $ROOT/include/fcall.h diff --git a/lib9/mkfile-Nt b/lib9/mkfile-Nt new file mode 100644 index 00000000..28e714ba --- /dev/null +++ b/lib9/mkfile-Nt @@ -0,0 +1,8 @@ +TARGFILES=\ + $IMPORTFILES\ + dirstat-Nt.$O\ + errstr-Nt.$O\ + getuser-Nt.$O\ + getwd-Nt.$O\ + setbinmode-Nt.$O\ + lock-Nt-386.$O\ diff --git a/lib9/mkfile-Plan9 b/lib9/mkfile-Plan9 new file mode 100644 index 00000000..081a2152 --- /dev/null +++ b/lib9/mkfile-Plan9 @@ -0,0 +1,2 @@ +TARGFILES=errstr-Plan9.$O\ + diff --git a/lib9/mkfile-Posix b/lib9/mkfile-Posix new file mode 100644 index 00000000..085c665b --- /dev/null +++ b/lib9/mkfile-Posix @@ -0,0 +1,8 @@ +TARGFILES=\ + $IMPORTFILES\ + dirstat-posix.$O\ + errstr-posix.$O\ + getuser-posix.$O\ + getcallerpc-$SYSTARG-$OBJTYPE.$O\ + getwd-posix.$O\ + sbrk-posix.$O\ diff --git a/lib9/nulldir.c b/lib9/nulldir.c new file mode 100644 index 00000000..26ca3b22 --- /dev/null +++ b/lib9/nulldir.c @@ -0,0 +1,8 @@ +#include "lib9.h" + +void +nulldir(Dir *d) +{ + memset(d, ~0, sizeof(Dir)); + d->name = d->uid = d->gid = d->muid = ""; +} diff --git a/lib9/pow10.c b/lib9/pow10.c new file mode 100644 index 00000000..84971a27 --- /dev/null +++ b/lib9/pow10.c @@ -0,0 +1,44 @@ +#ifdef LINUX_386 +#define _MATH_H +#endif + +#include "lib9.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 +pow10(int n) +{ + int m; + + if(n < 0) { + n = -n; + if(n < sizeof(tab)/sizeof(tab[0])) + return 1/tab[n]; + m = n/2; + return pow10(-m) * pow10(m-n); + } + if(n < sizeof(tab)/sizeof(tab[0])) + return tab[n]; + m = n/2; + return pow10(m) * pow10(n-m); +} diff --git a/lib9/print.c b/lib9/print.c new file mode 100644 index 00000000..65feb976 --- /dev/null +++ b/lib9/print.c @@ -0,0 +1,26 @@ +/* + * 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 "lib9.h" + +int +print(char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vfprint(1, fmt, args); + va_end(args); + return n; +} diff --git a/lib9/qsort.c b/lib9/qsort.c new file mode 100644 index 00000000..3388891c --- /dev/null +++ b/lib9/qsort.c @@ -0,0 +1,122 @@ +/* + * qsort -- simple quicksort + */ + +typedef +struct +{ + int (*cmp)(void*, void*); + void (*swap)(char*, char*, long); + long es; +} Sort; + +static void +swapb(char *i, char *j, long es) +{ + char c; + + do { + c = *i; + *i++ = *j; + *j++ = c; + es--; + } while(es != 0); + +} + +static void +swapi(char *ii, char *ij, long es) +{ + long *i, *j, c; + + i = (long*)ii; + j = (long*)ij; + do { + c = *i; + *i++ = *j; + *j++ = c; + es -= sizeof(long); + } while(es != 0); +} + +static char* +pivot(char *a, long n, Sort *p) +{ + long j; + char *pi, *pj, *pk; + + j = n/6 * p->es; + pi = a + j; /* 1/6 */ + j += j; + pj = pi + j; /* 1/2 */ + pk = pj + j; /* 5/6 */ + if(p->cmp(pi, pj) < 0) { + if(p->cmp(pi, pk) < 0) { + if(p->cmp(pj, pk) < 0) + return pj; + return pk; + } + return pi; + } + if(p->cmp(pj, pk) < 0) { + if(p->cmp(pi, pk) < 0) + return pi; + return pk; + } + return pj; +} + +static void +qsorts(char *a, long n, Sort *p) +{ + long j, es; + char *pi, *pj, *pn; + + es = p->es; + while(n > 1) { + if(n > 10) { + pi = pivot(a, n, p); + } else + pi = a + (n>>1)*es; + + p->swap(a, pi, es); + pi = a; + pn = a + n*es; + pj = pn; + for(;;) { + do + pi += es; + while(pi < pn && p->cmp(pi, a) < 0); + do + pj -= es; + while(pj > a && p->cmp(pj, a) > 0); + if(pj < pi) + break; + p->swap(pi, pj, es); + } + p->swap(a, pj, es); + j = (pj - a) / es; + + n = n-j-1; + if(j >= n) { + qsorts(a, j, p); + a += (j+1)*es; + } else { + qsorts(a + (j+1)*es, n, p); + n = j; + } + } +} + +void +qsort(void *va, long n, long es, int (*cmp)(void*, void*)) +{ + Sort s; + + s.cmp = cmp; + s.es = es; + s.swap = swapi; + if(((long)va | es) % sizeof(long)) + s.swap = swapb; + qsorts((char*)va, n, &s); +} diff --git a/lib9/readn.c b/lib9/readn.c new file mode 100644 index 00000000..74554264 --- /dev/null +++ b/lib9/readn.c @@ -0,0 +1,21 @@ +#include "lib9.h" + +long +readn(int f, void *av, long n) +{ + char *a; + long m, t; + + a = av; + t = 0; + while(t < n){ + m = read(f, a+t, n-t); + if(m <= 0){ + if(t == 0) + return m; + break; + } + t += m; + } + return t; +} diff --git a/lib9/rerrstr.c b/lib9/rerrstr.c new file mode 100644 index 00000000..ebddaf9b --- /dev/null +++ b/lib9/rerrstr.c @@ -0,0 +1,12 @@ +#include "lib9.h" + +void +rerrstr(char *buf, uint nbuf) +{ + char tmp[ERRMAX]; + + tmp[0] = 0; + errstr(tmp, sizeof tmp); + utfecpy(buf, buf+nbuf, tmp); + errstr(tmp, sizeof tmp); +} diff --git a/lib9/rune.c b/lib9/rune.c new file mode 100644 index 00000000..3dcff0b4 --- /dev/null +++ b/lib9/rune.c @@ -0,0 +1,162 @@ +#include "lib9.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) +{ + if(c <= Rune1) + return 1; + if(c <= Rune2) + return 2; + return 3; +} + +int +runenlen(Rune *r, int l) +{ + int n; + long c; + + n = 0; + while(l--) { + c = *r++; + if(c <= Rune1) + n += 1; + else + if(c <= Rune2) + n += 2; + else + n += 3; + } + return n; +} + +int +fullrune(char *str, int n) +{ + int c; + + if(n > 0) { + c = *(uchar*)str; + if(c < Tx) + return 1; + if(n > 1) + if(c < T3 || n > 2) + return 1; + } + return 0; +} diff --git a/lib9/runestrlen.c b/lib9/runestrlen.c new file mode 100644 index 00000000..e1cd84ac --- /dev/null +++ b/lib9/runestrlen.c @@ -0,0 +1,13 @@ +#include "lib9.h" + + +long +runestrlen(Rune *s) +{ + int i; + + i = 0; + while(*s++) + i++; + return i; +} diff --git a/lib9/sbrk-posix.c b/lib9/sbrk-posix.c new file mode 100644 index 00000000..c21cd2ff --- /dev/null +++ b/lib9/sbrk-posix.c @@ -0,0 +1,48 @@ +#ifdef __APPLE_CC__ /* look for a better way */ +#include "lib9.h" +#undef _POSIX_C_SOURCE +#undef getwd + +#include <unistd.h> +#include <pthread.h> +#include <time.h> +#include <termios.h> +#include <signal.h> +#include <pwd.h> +#include <sys/resource.h> +#include <sys/time.h> + +#include <sys/socket.h> +#include <sched.h> +#include <errno.h> +#include <sys/ucontext.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <mach/mach_init.h> + +#include <mach/task.h> + +#include <mach/vm_map.h> + + +__typeof__(sbrk(0)) +sbrk(int size) +{ + void *brk; + kern_return_t err; + + err = vm_allocate( (vm_map_t) mach_task_self(), + (vm_address_t *)&brk, + size, + VM_FLAGS_ANYWHERE); + if (err != KERN_SUCCESS) + brk = (void*)-1; + + return brk; +} +#else +/* dummy function for everyone else, in case its ar complains about empty files */ +void __fakesbrk(void){} +#endif diff --git a/lib9/seek.c b/lib9/seek.c new file mode 100644 index 00000000..0fb5282a --- /dev/null +++ b/lib9/seek.c @@ -0,0 +1,9 @@ +#include "lib9.h" +#include <sys/types.h> +#include <fcntl.h> + +vlong +seek(int fd, vlong where, int from) +{ + return lseek(fd, where, from); +} diff --git a/lib9/seprint.c b/lib9/seprint.c new file mode 100644 index 00000000..7dadad62 --- /dev/null +++ b/lib9/seprint.c @@ -0,0 +1,26 @@ +/* + * 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 "lib9.h" + +char* +seprint(char *buf, char *e, char *fmt, ...) +{ + char *p; + va_list args; + + va_start(args, fmt); + p = vseprint(buf, e, fmt, args); + va_end(args); + return p; +} diff --git a/lib9/setbinmode-Nt.c b/lib9/setbinmode-Nt.c new file mode 100644 index 00000000..48c5f700 --- /dev/null +++ b/lib9/setbinmode-Nt.c @@ -0,0 +1,9 @@ +#include "lib9.h" + +void +setbinmode(void) +{ + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + _setmode(2, _O_BINARY); +} diff --git a/lib9/smprint.c b/lib9/smprint.c new file mode 100644 index 00000000..ecb55492 --- /dev/null +++ b/lib9/smprint.c @@ -0,0 +1,26 @@ +/* + * 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 "lib9.h" + +char* +smprint(char *fmt, ...) +{ + va_list args; + char *p; + + va_start(args, fmt); + p = vsmprint(fmt, args); + va_end(args); + return p; +} diff --git a/lib9/snprint.c b/lib9/snprint.c new file mode 100644 index 00000000..6e65c70c --- /dev/null +++ b/lib9/snprint.c @@ -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 "lib9.h" + +int +snprint(char *buf, int len, char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vsnprint(buf, len, fmt, args); + va_end(args); + return n; +} + diff --git a/lib9/sprint.c b/lib9/sprint.c new file mode 100644 index 00000000..86c79a32 --- /dev/null +++ b/lib9/sprint.c @@ -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 "lib9.h" + +int +sprint(char *buf, char *fmt, ...) +{ + int n; + uint len; + va_list args; + + len = 1<<30; /* big number, but sprint is deprecated anyway */ + /* + * the stack might be near the top of memory, so + * we must be sure not to overflow a 32-bit pointer. + */ + if(buf+len < buf) + len = -(uint)buf-1; + + va_start(args, fmt); + n = vsnprint(buf, len, fmt, args); + va_end(args); + return n; +} diff --git a/lib9/strdup.c b/lib9/strdup.c new file mode 100644 index 00000000..2473f8f5 --- /dev/null +++ b/lib9/strdup.c @@ -0,0 +1,12 @@ +#include "lib9.h" + +char* +strdup(const char *s) +{ + char *os; + + os = malloc(strlen(s) + 1); + if(os == 0) + return 0; + return strcpy(os, s); +} diff --git a/lib9/strecpy.c b/lib9/strecpy.c new file mode 100644 index 00000000..64b23294 --- /dev/null +++ b/lib9/strecpy.c @@ -0,0 +1,16 @@ +#include "lib9.h" + +char* +strecpy(char *to, char *e, char *from) +{ + if(to >= e) + return to; + to = memccpy(to, from, '\0', e - to); + if(to == nil){ + to = e - 1; + *to = '\0'; + }else{ + to--; + } + return to; +} diff --git a/lib9/strtoll.c b/lib9/strtoll.c new file mode 100644 index 00000000..ff98e1c4 --- /dev/null +++ b/lib9/strtoll.c @@ -0,0 +1,81 @@ +#include "lib9.h" + +vlong +strtoll(const char *nptr, char **endptr, int base) +{ + const char *p; + vlong n; + int c, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + + /* + * White space + */ + for(;;p++){ + switch(*p){ + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p=='-' || *p=='+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base==0){ + if(*p != '0') + base = 10; + else{ + base = 8; + if(p[1]=='x' || p[1]=='X'){ + p += 2; + base = 16; + } + } + }else if(base==16 && *p=='0'){ + if(p[1]=='x' || p[1]=='X') + p += 2; + }else if(base<0 || 36<base) + goto Return; + + /* + * Non-empty sequence of digits + */ + for(;; p++,ndig++){ + c = *p; + v = base; + if('0'<=c && c<='9') + v = c - '0'; + else if('a'<=c && c<='z') + v = c - 'a' + 10; + else if('A'<=c && c<='Z') + v = c - 'A' + 10; + if(v >= base) + break; + n = n*base + v; + } + Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = (char*) p; + if(neg) + return -n; + return n; +} diff --git a/lib9/sysfatal.c b/lib9/sysfatal.c new file mode 100644 index 00000000..bb1f8e85 --- /dev/null +++ b/lib9/sysfatal.c @@ -0,0 +1,28 @@ +#include "lib9.h" + + + +static void +_sysfatalimpl(char *fmt, va_list arg) +{ + char buf[1024]; + + vseprint(buf, buf+sizeof(buf), fmt, arg); + if(argv0) + fprint(2, "%s: %s\n", argv0, buf); + else + fprint(2, "%s\n", buf); + exits(buf); +} + +void (*_sysfatal)(char *fmt, va_list arg) = _sysfatalimpl; + +void +sysfatal(char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + (*_sysfatal)(fmt, arg); + va_end(arg); +} diff --git a/lib9/tokenize.c b/lib9/tokenize.c new file mode 100644 index 00000000..1b222c52 --- /dev/null +++ b/lib9/tokenize.c @@ -0,0 +1,58 @@ +#include "lib9.h" + +static char qsep[] = " \t\r\n"; + +static char* +qtoken(char *s) +{ + int quoting; + char *t; + + quoting = 0; + t = s; /* s is output string, t is input string */ + while(*t!='\0' && (quoting || utfrune(qsep, *t)==nil)){ + if(*t != '\''){ + *s++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s++ = *t++; + } + if(*s != '\0'){ + *s = '\0'; + if(t == s) + t++; + } + return t; +} + +int +tokenize(char *s, char **args, int maxargs) +{ + int nargs; + + for(nargs=0; nargs<maxargs; nargs++){ + while(*s!='\0' && utfrune(qsep, *s)!=nil) + s++; + if(*s == '\0') + break; + args[nargs] = s; + s = qtoken(s); + } + + return nargs; +} diff --git a/lib9/u16.c b/lib9/u16.c new file mode 100644 index 00000000..d9f41e46 --- /dev/null +++ b/lib9/u16.c @@ -0,0 +1,52 @@ +#include <lib9.h> +static char t16e[] = "0123456789ABCDEF"; + +int +dec16(uchar *out, int lim, char *in, int n) +{ + int c, w = 0, i = 0; + uchar *start = out; + uchar *eout = out + lim; + + while(n-- > 0){ + c = *in++; + if('0' <= c && c <= '9') + c = c - '0'; + else if('a' <= c && c <= 'z') + c = c - 'a' + 10; + else if('A' <= c && c <= 'Z') + c = c - 'A' + 10; + else + continue; + w = (w<<4) + c; + i++; + if(i == 2){ + if(out + 1 > eout) + goto exhausted; + *out++ = w; + w = 0; + i = 0; + } + } +exhausted: + return out - start; +} + +int +enc16(char *out, int lim, uchar *in, int n) +{ + uint c; + char *eout = out + lim; + char *start = out; + + while(n-- > 0){ + c = *in++; + if(out + 2 >= eout) + goto exhausted; + *out++ = t16e[c>>4]; + *out++ = t16e[c&0xf]; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/lib9/u32.c b/lib9/u32.c new file mode 100644 index 00000000..1eb0c6e0 --- /dev/null +++ b/lib9/u32.c @@ -0,0 +1,109 @@ +#include <lib9.h> + +int +dec32(uchar *dest, int ndest, char *src, int nsrc) +{ + char *s, *tab; + uchar *start; + int i, u[8]; + + if(ndest+1 < (5*nsrc+7)/8) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=8){ + for(i=0; i<8; i++){ + s = strchr(tab,(int)src[i]); + u[i] = s ? s-tab : 0; + } + *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + *dest++ = ((0x7 & u[6])<<5) | u[7]; + src += 8; + nsrc -= 8; + } + if(nsrc > 0){ + if(nsrc == 1 || nsrc == 3 || nsrc == 6) + return -1; + for(i=0; i<nsrc; i++){ + s = strchr(tab,(int)src[i]); + u[i] = s ? s-tab : 0; + } + *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); + if(nsrc == 2) + goto out; + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + if(nsrc == 4) + goto out; + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + if(nsrc == 5) + goto out; + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + } +out: + return dest-start; +} + +int +enc32(char *dest, int ndest, uchar *src, int nsrc) +{ + char *tab, *start; + int j; + + if(ndest <= (8*nsrc+4)/5 ) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=5){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5)); + *dest++ = tab[j]; + j = (0x1f & (src[4])); + *dest++ = tab[j]; + src += 5; + nsrc -= 5; + } + if(nsrc){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)); + if(nsrc == 1) + goto out; + j |= (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + if(nsrc == 2) + goto out; + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)); + if(nsrc == 3) + goto out; + j |= (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)); + if(nsrc == 4) + goto out; + j |= (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)); +out: + *dest++ = tab[j]; + } + *dest = 0; + return dest-start; +} diff --git a/lib9/u64.c b/lib9/u64.c new file mode 100644 index 00000000..a17bdf1d --- /dev/null +++ b/lib9/u64.c @@ -0,0 +1,126 @@ +#include <lib9.h> + +enum { + INVAL= 255 +}; + +static uchar t64d[256] = { + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL +}; +static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +int +dec64(uchar *out, int lim, char *in, int n) +{ + ulong b24; + uchar *start = out; + uchar *e = out + lim; + int i, c; + + b24 = 0; + i = 0; + while(n-- > 0){ + + c = t64d[*(uchar*)in++]; + if(c == INVAL) + continue; + switch(i){ + case 0: + b24 = c<<18; + break; + case 1: + b24 |= c<<12; + break; + case 2: + b24 |= c<<6; + break; + case 3: + if(out + 3 > e) + goto exhausted; + + b24 |= c; + *out++ = b24>>16; + *out++ = b24>>8; + *out++ = b24; + i = -1; + break; + } + i++; + } + switch(i){ + case 2: + if(out + 1 > e) + goto exhausted; + *out++ = b24>>16; + break; + case 3: + if(out + 2 > e) + goto exhausted; + *out++ = b24>>16; + *out++ = b24>>8; + break; + } +exhausted: + return out - start; +} + +int +enc64(char *out, int lim, uchar *in, int n) +{ + int i; + ulong b24; + char *start = out; + char *e = out + lim; + + for(i = n/3; i > 0; i--){ + b24 = (*in++)<<16; + b24 |= (*in++)<<8; + b24 |= *in++; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = t64e[(b24)&0x3f]; + } + + switch(n%3){ + case 2: + b24 = (*in++)<<16; + b24 |= (*in)<<8; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = '='; + break; + case 1: + b24 = (*in)<<16; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = '='; + *out++ = '='; + break; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/lib9/utfecpy.c b/lib9/utfecpy.c new file mode 100644 index 00000000..8ccb841c --- /dev/null +++ b/lib9/utfecpy.c @@ -0,0 +1,20 @@ +#include "lib9.h" + +char* +utfecpy(char *to, char *e, char *from) +{ + char *end; + + if(to >= e) + return to; + end = memccpy(to, from, '\0', e - to); + if(end == nil){ + end = e-1; + while(end>to && (*--end&0xC0)==0x80) + ; + *end = '\0'; + }else{ + end--; + } + return end; +} diff --git a/lib9/utflen.c b/lib9/utflen.c new file mode 100644 index 00000000..815cc040 --- /dev/null +++ b/lib9/utflen.c @@ -0,0 +1,22 @@ +#include "lib9.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; +} diff --git a/lib9/utfnlen.c b/lib9/utfnlen.c new file mode 100644 index 00000000..02623f51 --- /dev/null +++ b/lib9/utfnlen.c @@ -0,0 +1,25 @@ +#include "lib9.h" + +int +utfnlen(char *s, long m) +{ + int c; + long n; + Rune rune; + char *es; + + es = s + m; + for(n = 0; s < es; n++) { + c = *(uchar*)s; + if(c < Runeself){ + if(c == '\0') + break; + s++; + continue; + } + if(!fullrune(s, es-s)) + break; + s += chartorune(&rune, s); + } + return n; +} diff --git a/lib9/utfrrune.c b/lib9/utfrrune.c new file mode 100644 index 00000000..b6e8f2fc --- /dev/null +++ b/lib9/utfrrune.c @@ -0,0 +1,30 @@ +#include "lib9.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; +} diff --git a/lib9/utfrune.c b/lib9/utfrune.c new file mode 100644 index 00000000..a2737471 --- /dev/null +++ b/lib9/utfrune.c @@ -0,0 +1,29 @@ +#include "lib9.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; +} diff --git a/lib9/vfprint.c b/lib9/vfprint.c new file mode 100644 index 00000000..eeea55d1 --- /dev/null +++ b/lib9/vfprint.c @@ -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 "lib9.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; +} + +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; +} diff --git a/lib9/vseprint.c b/lib9/vseprint.c new file mode 100644 index 00000000..6f478960 --- /dev/null +++ b/lib9/vseprint.c @@ -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 "lib9.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 = nil; + f.farg = nil; + f.nfmt = 0; + f.args = args; + dofmt(&f, fmt); + *(char*)f.to = '\0'; + return f.to; +} + diff --git a/lib9/vsmprint.c b/lib9/vsmprint.c new file mode 100644 index 00000000..44789be5 --- /dev/null +++ b/lib9/vsmprint.c @@ -0,0 +1,74 @@ +/* + * 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 "lib9.h" +#include "fmtdef.h" + +static int +fmtStrFlush(Fmt *f) +{ + char *s; + int n; + + n = (int)f->farg; + n += 256; + f->farg = (void*)n; + s = f->start; + f->start = realloc(s, n); + if(f->start == nil){ + free(s); + f->to = nil; + f->stop = nil; + 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; +} + +/* + * 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 f.start; +} diff --git a/lib9/vsnprint.c b/lib9/vsnprint.c new file mode 100644 index 00000000..841d142c --- /dev/null +++ b/lib9/vsnprint.c @@ -0,0 +1,34 @@ +/* + * 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 "lib9.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 = nil; + f.farg = nil; + f.nfmt = 0; + f.args = args; + dofmt(&f, fmt); + *(char*)f.to = '\0'; + return (char*)f.to - buf; +} |
