a
This commit is contained in:
89
libc/Makefile
Normal file
89
libc/Makefile
Normal file
@ -0,0 +1,89 @@
|
||||
LIB=libc.a
|
||||
CC=gcc
|
||||
CFLAGS=-I../include -I. -c -ggdb -D_THREAD_SAFE -pthread
|
||||
O=o
|
||||
|
||||
OFILES=\
|
||||
charstod.$O\
|
||||
cleanname.$O\
|
||||
convD2M.$O\
|
||||
convM2D.$O\
|
||||
convM2S.$O\
|
||||
convS2M.$O\
|
||||
crypt.$O\
|
||||
dial.$O\
|
||||
dirfstat.$O\
|
||||
dirfwstat.$O\
|
||||
dirmodefmt.$O\
|
||||
dirstat.$O\
|
||||
dirwstat.$O\
|
||||
dofmt.$O\
|
||||
dorfmt.$O\
|
||||
fcallfmt.$O\
|
||||
fltfmt.$O\
|
||||
fmt.$O\
|
||||
fmtfd.$O\
|
||||
fmtlock.$O\
|
||||
fmtprint.$O\
|
||||
fmtquote.$O\
|
||||
fmtrune.$O\
|
||||
fmtstr.$O\
|
||||
fmtvprint.$O\
|
||||
fprint.$O\
|
||||
frand.$O\
|
||||
getfields.$O\
|
||||
getpid.$O\
|
||||
lnrand.$O\
|
||||
lock.$O\
|
||||
lrand.$O\
|
||||
mallocz.$O\
|
||||
nan64.$O\
|
||||
netmkaddr.$O\
|
||||
nrand.$O\
|
||||
nsec.$O\
|
||||
pow10.$O\
|
||||
pushssl.$O\
|
||||
read9pmsg.$O\
|
||||
readn.$O\
|
||||
rune.$O\
|
||||
runefmtstr.$O\
|
||||
runeseprint.$O\
|
||||
runesmprint.$O\
|
||||
runesnprint.$O\
|
||||
runesprint.$O\
|
||||
runetype.$O\
|
||||
runevseprint.$O\
|
||||
runevsmprint.$O\
|
||||
runevsnprint.$O\
|
||||
seprint.$O\
|
||||
smprint.$O\
|
||||
snprint.$O\
|
||||
sprint.$O\
|
||||
strecpy.$O\
|
||||
strtod.$O\
|
||||
strtoll.$O\
|
||||
sysfatal.$O\
|
||||
time.$O\
|
||||
tokenize.$O\
|
||||
truerand.$O\
|
||||
u16.$O\
|
||||
u32.$O\
|
||||
u64.$O\
|
||||
utfecpy.$O\
|
||||
utflen.$O\
|
||||
utfnlen.$O\
|
||||
utfrrune.$O\
|
||||
utfrune.$O\
|
||||
utfutf.$O\
|
||||
vfprint.$O\
|
||||
vseprint.$O\
|
||||
vsmprint.$O\
|
||||
vsnprint.$O
|
||||
|
||||
$(LIB): $(OFILES)
|
||||
ar r $(LIB) $(OFILES)
|
||||
ranlib $(LIB)
|
||||
|
||||
%.$O: %.c
|
||||
$(CC) $(CFLAGS) $*.c
|
||||
|
81
libc/charstod.c
Normal file
81
libc/charstod.c
Normal file
@ -0,0 +1,81 @@
|
||||
#include <u.h>
|
||||
#include <libc.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.
|
||||
*/
|
||||
|
||||
#define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp)
|
||||
|
||||
double
|
||||
charstod(int(*f)(void*), void *vp)
|
||||
{
|
||||
char str[400], *s, *e, *start;
|
||||
int c;
|
||||
|
||||
s = str;
|
||||
e = str + sizeof str - 1;
|
||||
c = (*f)(vp);
|
||||
while(c == ' ' || c == '\t')
|
||||
c = (*f)(vp);
|
||||
if(c == '-' || c == '+'){
|
||||
ADVANCE;
|
||||
}
|
||||
start = s;
|
||||
while(c >= '0' && c <= '9'){
|
||||
ADVANCE;
|
||||
}
|
||||
if(c == '.'){
|
||||
ADVANCE;
|
||||
while(c >= '0' && c <= '9'){
|
||||
ADVANCE;
|
||||
}
|
||||
}
|
||||
if(s > start && (c == 'e' || c == 'E')){
|
||||
ADVANCE;
|
||||
if(c == '-' || c == '+'){
|
||||
ADVANCE;
|
||||
}
|
||||
while(c >= '0' && c <= '9'){
|
||||
ADVANCE;
|
||||
}
|
||||
}else if(s == start && (c == 'i' || c == 'I')){
|
||||
ADVANCE;
|
||||
if(c != 'n' && c != 'N')
|
||||
return NaN();
|
||||
ADVANCE;
|
||||
if(c != 'f' && c != 'F')
|
||||
return NaN();
|
||||
ADVANCE;
|
||||
if(c != 'i' && c != 'I')
|
||||
return NaN();
|
||||
ADVANCE;
|
||||
if(c != 'n' && c != 'N')
|
||||
return NaN();
|
||||
ADVANCE;
|
||||
if(c != 'i' && c != 'I')
|
||||
return NaN();
|
||||
ADVANCE;
|
||||
if(c != 't' && c != 'T')
|
||||
return NaN();
|
||||
ADVANCE;
|
||||
if(c != 'y' && c != 'Y')
|
||||
return NaN();
|
||||
ADVANCE; /* so caller can back up uniformly */
|
||||
USED(c);
|
||||
}else if(s == str && (c == 'n' || c == 'N')){
|
||||
ADVANCE;
|
||||
if(c != 'a' && c != 'A')
|
||||
return NaN();
|
||||
ADVANCE;
|
||||
if(c != 'n' && c != 'N')
|
||||
return NaN();
|
||||
ADVANCE; /* so caller can back up uniformly */
|
||||
USED(c);
|
||||
}
|
||||
*s = 0;
|
||||
return strtod(str, &s);
|
||||
}
|
52
libc/cleanname.c
Normal file
52
libc/cleanname.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* In place, rewrite name to compress multiple /, eliminate ., and process ..
|
||||
*/
|
||||
#define SEP(x) ((x)=='/' || (x) == 0)
|
||||
char*
|
||||
cleanname(char *name)
|
||||
{
|
||||
char *p, *q, *dotdot;
|
||||
int rooted;
|
||||
|
||||
rooted = name[0] == '/';
|
||||
|
||||
/*
|
||||
* invariants:
|
||||
* p points at beginning of path element we're considering.
|
||||
* q points just past the last path element we wrote (no slash).
|
||||
* dotdot points just past the point where .. cannot backtrack
|
||||
* any further (no slash).
|
||||
*/
|
||||
p = q = dotdot = name+rooted;
|
||||
while(*p) {
|
||||
if(p[0] == '/') /* null element */
|
||||
p++;
|
||||
else if(p[0] == '.' && SEP(p[1]))
|
||||
p += 1; /* don't count the separator in case it is nul */
|
||||
else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
|
||||
p += 2;
|
||||
if(q > dotdot) { /* can backtrack */
|
||||
while(--q > dotdot && *q != '/')
|
||||
;
|
||||
} else if(!rooted) { /* /.. is / but ./../ is .. */
|
||||
if(q != name)
|
||||
*q++ = '/';
|
||||
*q++ = '.';
|
||||
*q++ = '.';
|
||||
dotdot = q;
|
||||
}
|
||||
} else { /* real path element */
|
||||
if(q != name+rooted)
|
||||
*q++ = '/';
|
||||
while((*q = *p) != '/' && *q != 0)
|
||||
p++, q++;
|
||||
}
|
||||
}
|
||||
if(q == name) /* empty string is really ``.'' */
|
||||
*q++ = '.';
|
||||
*q = '\0';
|
||||
return name;
|
||||
}
|
95
libc/convD2M.c
Normal file
95
libc/convD2M.c
Normal file
@ -0,0 +1,95 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
94
libc/convM2D.c
Normal file
94
libc/convM2D.c
Normal file
@ -0,0 +1,94 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
315
libc/convM2S.c
Normal file
315
libc/convM2S.c
Normal file
@ -0,0 +1,315 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
386
libc/convS2M.c
Normal file
386
libc/convS2M.c
Normal file
@ -0,0 +1,386 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
68
libc/crypt.c
Normal file
68
libc/crypt.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Data Encryption Standard
|
||||
* D.P.Mitchell 83/06/08.
|
||||
*
|
||||
* block_cipher(key, block, decrypting)
|
||||
*
|
||||
* these routines use the non-standard 7 byte format
|
||||
* for DES keys.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include <libsec.h>
|
||||
|
||||
/*
|
||||
* destructively encrypt the buffer, which
|
||||
* must be at least 8 characters long.
|
||||
*/
|
||||
int
|
||||
encrypt(void *key, void *vbuf, int n)
|
||||
{
|
||||
ulong ekey[32];
|
||||
uchar *buf;
|
||||
int i, r;
|
||||
|
||||
if(n < 8)
|
||||
return 0;
|
||||
key_setup(key, ekey);
|
||||
buf = vbuf;
|
||||
n--;
|
||||
r = n % 7;
|
||||
n /= 7;
|
||||
for(i = 0; i < n; i++){
|
||||
block_cipher(ekey, buf, 0);
|
||||
buf += 7;
|
||||
}
|
||||
if(r)
|
||||
block_cipher(ekey, buf - 7 + r, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* destructively decrypt the buffer, which
|
||||
* must be at least 8 characters long.
|
||||
*/
|
||||
int
|
||||
decrypt(void *key, void *vbuf, int n)
|
||||
{
|
||||
ulong ekey[128];
|
||||
uchar *buf;
|
||||
int i, r;
|
||||
|
||||
if(n < 8)
|
||||
return 0;
|
||||
key_setup(key, ekey);
|
||||
buf = vbuf;
|
||||
n--;
|
||||
r = n % 7;
|
||||
n /= 7;
|
||||
buf += n * 7;
|
||||
if(r)
|
||||
block_cipher(ekey, buf - 7 + r, 1);
|
||||
for(i = 0; i < n; i++){
|
||||
buf -= 7;
|
||||
block_cipher(ekey, buf, 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
209
libc/dial.c
Normal file
209
libc/dial.c
Normal file
@ -0,0 +1,209 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
typedef struct DS DS;
|
||||
|
||||
static int call(char*, char*, DS*);
|
||||
static int csdial(DS*);
|
||||
static void _dial_string_parse(char*, DS*);
|
||||
|
||||
enum
|
||||
{
|
||||
Maxstring = 128,
|
||||
Maxpath = 256,
|
||||
};
|
||||
|
||||
struct DS {
|
||||
/* dist string */
|
||||
char buf[Maxstring];
|
||||
char *netdir;
|
||||
char *proto;
|
||||
char *rem;
|
||||
|
||||
/* other args */
|
||||
char *local;
|
||||
char *dir;
|
||||
int *cfdp;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* the dialstring is of the form '[/net/]proto!dest'
|
||||
*/
|
||||
int
|
||||
dial(char *dest, char *local, char *dir, int *cfdp)
|
||||
{
|
||||
DS ds;
|
||||
int rv;
|
||||
char err[ERRMAX], alterr[ERRMAX];
|
||||
|
||||
ds.local = local;
|
||||
ds.dir = dir;
|
||||
ds.cfdp = cfdp;
|
||||
|
||||
_dial_string_parse(dest, &ds);
|
||||
if(ds.netdir)
|
||||
return csdial(&ds);
|
||||
|
||||
ds.netdir = "/net";
|
||||
rv = csdial(&ds);
|
||||
if(rv >= 0)
|
||||
return rv;
|
||||
err[0] = '\0';
|
||||
errstr(err, sizeof err);
|
||||
if(strstr(err, "refused") != 0){
|
||||
werrstr("%s", err);
|
||||
return rv;
|
||||
}
|
||||
ds.netdir = "/net.alt";
|
||||
rv = csdial(&ds);
|
||||
if(rv >= 0)
|
||||
return rv;
|
||||
|
||||
alterr[0] = 0;
|
||||
errstr(alterr, sizeof alterr);
|
||||
if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
|
||||
werrstr("%s", err);
|
||||
else
|
||||
werrstr("%s", alterr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
csdial(DS *ds)
|
||||
{
|
||||
int n, fd, rv;
|
||||
char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
|
||||
|
||||
/*
|
||||
* open connection server
|
||||
*/
|
||||
snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
|
||||
fd = open(buf, ORDWR);
|
||||
if(fd < 0){
|
||||
/* no connection server, don't translate */
|
||||
snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
|
||||
return call(clone, ds->rem, ds);
|
||||
}
|
||||
|
||||
/*
|
||||
* ask connection server to translate
|
||||
*/
|
||||
snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
|
||||
if(write(fd, buf, strlen(buf)) < 0){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* loop through each address from the connection server till
|
||||
* we get one that works.
|
||||
*/
|
||||
*besterr = 0;
|
||||
rv = -1;
|
||||
seek(fd, 0, 0);
|
||||
strcpy(err, "cs gave empty translation list");
|
||||
while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
|
||||
buf[n] = 0;
|
||||
p = strchr(buf, ' ');
|
||||
if(p == 0)
|
||||
continue;
|
||||
*p++ = 0;
|
||||
rv = call(buf, p, ds);
|
||||
if(rv >= 0)
|
||||
break;
|
||||
err[0] = '\0';
|
||||
errstr(err, sizeof err);
|
||||
if(strstr(err, "does not exist") == 0)
|
||||
strcpy(besterr, err);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if(rv < 0 && *besterr)
|
||||
werrstr("%s", besterr);
|
||||
else
|
||||
werrstr("%s", err);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
call(char *clone, char *dest, DS *ds)
|
||||
{
|
||||
int fd, cfd, n;
|
||||
char name[Maxpath], data[Maxpath], *p;
|
||||
|
||||
cfd = open(clone, ORDWR);
|
||||
if(cfd < 0)
|
||||
return -1;
|
||||
|
||||
/* get directory name */
|
||||
n = read(cfd, name, sizeof(name)-1);
|
||||
if(n < 0){
|
||||
close(cfd);
|
||||
return -1;
|
||||
}
|
||||
name[n] = 0;
|
||||
for(p = name; *p == ' '; p++)
|
||||
;
|
||||
snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
|
||||
p = strrchr(clone, '/');
|
||||
*p = 0;
|
||||
if(ds->dir)
|
||||
snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name);
|
||||
snprint(data, sizeof(data), "%s/%s/data", clone, name);
|
||||
|
||||
/* connect */
|
||||
if(ds->local)
|
||||
snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
|
||||
else
|
||||
snprint(name, sizeof(name), "connect %s", dest);
|
||||
if(write(cfd, name, strlen(name)) < 0){
|
||||
close(cfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open data connection */
|
||||
fd = open(data, ORDWR);
|
||||
if(fd < 0){
|
||||
print("open %s: %r\n", data);
|
||||
close(cfd);
|
||||
return -1;
|
||||
}
|
||||
if(ds->cfdp)
|
||||
*ds->cfdp = cfd;
|
||||
else
|
||||
close(cfd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse a dial string
|
||||
*/
|
||||
static void
|
||||
_dial_string_parse(char *str, DS *ds)
|
||||
{
|
||||
char *p, *p2;
|
||||
|
||||
strncpy(ds->buf, str, Maxstring);
|
||||
ds->buf[Maxstring-1] = 0;
|
||||
|
||||
p = strchr(ds->buf, '!');
|
||||
if(p == 0) {
|
||||
ds->netdir = 0;
|
||||
ds->proto = "net";
|
||||
ds->rem = ds->buf;
|
||||
} else {
|
||||
if(*ds->buf != '/' && *ds->buf != '#'){
|
||||
ds->netdir = 0;
|
||||
ds->proto = ds->buf;
|
||||
} else {
|
||||
for(p2 = p; *p2 != '/'; p2--)
|
||||
;
|
||||
*p2++ = 0;
|
||||
ds->netdir = ds->buf;
|
||||
ds->proto = p2;
|
||||
}
|
||||
*p = 0;
|
||||
ds->rem = p + 1;
|
||||
}
|
||||
}
|
37
libc/dirfstat.c
Normal file
37
libc/dirfstat.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
enum
|
||||
{
|
||||
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
|
||||
};
|
||||
|
||||
Dir*
|
||||
dirfstat(int fd)
|
||||
{
|
||||
Dir *d;
|
||||
uchar *buf;
|
||||
int n, nd, i;
|
||||
|
||||
nd = DIRSIZE;
|
||||
for(i=0; i<2; i++){ /* should work by the second try */
|
||||
d = malloc(sizeof(Dir) + BIT16SZ + nd);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
buf = (uchar*)&d[1];
|
||||
n = fstat(fd, buf, BIT16SZ+nd);
|
||||
if(n < BIT16SZ){
|
||||
free(d);
|
||||
return nil;
|
||||
}
|
||||
nd = GBIT16(buf); /* upper bound on size of Dir + strings */
|
||||
if(nd <= n){
|
||||
convM2D(buf, n, d, (char*)&d[1]);
|
||||
return d;
|
||||
}
|
||||
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
|
||||
free(d);
|
||||
}
|
||||
return nil;
|
||||
}
|
19
libc/dirfwstat.c
Normal file
19
libc/dirfwstat.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
dirfwstat(int fd, Dir *d)
|
||||
{
|
||||
uchar *buf;
|
||||
int r;
|
||||
|
||||
r = sizeD2M(d);
|
||||
buf = malloc(r);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
convD2M(d, buf, r);
|
||||
r = fwstat(fd, buf, r);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
48
libc/dirmodefmt.c
Normal file
48
libc/dirmodefmt.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static char *modes[] =
|
||||
{
|
||||
"---",
|
||||
"--x",
|
||||
"-w-",
|
||||
"-wx",
|
||||
"r--",
|
||||
"r-x",
|
||||
"rw-",
|
||||
"rwx",
|
||||
};
|
||||
|
||||
static void
|
||||
rwx(long m, char *s)
|
||||
{
|
||||
strncpy(s, modes[m], 3);
|
||||
}
|
||||
|
||||
int
|
||||
dirmodefmt(Fmt *f)
|
||||
{
|
||||
static char buf[16];
|
||||
ulong m;
|
||||
|
||||
m = va_arg(f->args, ulong);
|
||||
|
||||
if(m & DMDIR)
|
||||
buf[0]='d';
|
||||
else if(m & DMAPPEND)
|
||||
buf[0]='a';
|
||||
else if(m & DMAUTH)
|
||||
buf[0]='A';
|
||||
else
|
||||
buf[0]='-';
|
||||
if(m & DMEXCL)
|
||||
buf[1]='l';
|
||||
else
|
||||
buf[1]='-';
|
||||
rwx((m>>6)&7, buf+2);
|
||||
rwx((m>>3)&7, buf+5);
|
||||
rwx((m>>0)&7, buf+8);
|
||||
buf[11] = 0;
|
||||
return fmtstrcpy(f, buf);
|
||||
}
|
37
libc/dirstat.c
Normal file
37
libc/dirstat.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
enum
|
||||
{
|
||||
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
|
||||
};
|
||||
|
||||
Dir*
|
||||
dirstat(char *name)
|
||||
{
|
||||
Dir *d;
|
||||
uchar *buf;
|
||||
int n, nd, i;
|
||||
|
||||
nd = DIRSIZE;
|
||||
for(i=0; i<2; i++){ /* should work by the second try */
|
||||
d = malloc(sizeof(Dir) + BIT16SZ + nd);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
buf = (uchar*)&d[1];
|
||||
n = stat(name, buf, BIT16SZ+nd);
|
||||
if(n < BIT16SZ){
|
||||
free(d);
|
||||
return nil;
|
||||
}
|
||||
nd = GBIT16((uchar*)buf); /* upper bound on size of Dir + strings */
|
||||
if(nd <= n){
|
||||
convM2D(buf, n, d, (char*)&d[1]);
|
||||
return d;
|
||||
}
|
||||
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
|
||||
free(d);
|
||||
}
|
||||
return nil;
|
||||
}
|
19
libc/dirwstat.c
Normal file
19
libc/dirwstat.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
dirwstat(char *name, Dir *d)
|
||||
{
|
||||
uchar *buf;
|
||||
int r;
|
||||
|
||||
r = sizeD2M(d);
|
||||
buf = malloc(r);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
convD2M(d, buf, r);
|
||||
r = wstat(name, buf, r);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
520
libc/dofmt.c
Normal file
520
libc/dofmt.c
Normal file
@ -0,0 +1,520 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/* format the output into f->to and return the number of characters fmted */
|
||||
int
|
||||
dofmt(Fmt *f, char *fmt)
|
||||
{
|
||||
Rune rune, *rt, *rs;
|
||||
int r;
|
||||
char *t, *s;
|
||||
int n, nfmt;
|
||||
|
||||
nfmt = f->nfmt;
|
||||
for(;;){
|
||||
if(f->runes){
|
||||
rt = 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;
|
||||
}
|
46
libc/dorfmt.c
Normal file
46
libc/dorfmt.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <u.h>
|
||||
#include <libc.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 */
|
||||
}
|
12
libc/errfmt.c
Normal file
12
libc/errfmt.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
int
|
||||
errfmt(Fmt *f)
|
||||
{
|
||||
char buf[ERRMAX];
|
||||
|
||||
rerrstr(buf, sizeof buf);
|
||||
return _fmtcpy(f, buf, utflen(buf), strlen(buf));
|
||||
}
|
234
libc/fcallfmt.c
Normal file
234
libc/fcallfmt.c
Normal file
@ -0,0 +1,234 @@
|
||||
#include <u.h>
|
||||
#include <libc.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') || 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;
|
||||
}
|
312
libc/fltfmt.c
Normal file
312
libc/fltfmt.c
Normal file
@ -0,0 +1,312 @@
|
||||
#include <u.h>
|
||||
#include <libc.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);
|
||||
}
|
193
libc/fmt.c
Normal file
193
libc/fmt.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
enum
|
||||
{
|
||||
Maxfmt = 64
|
||||
};
|
||||
|
||||
typedef struct Convfmt Convfmt;
|
||||
struct Convfmt
|
||||
{
|
||||
int c;
|
||||
volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
/* lock by calling _fmtlock, _fmtunlock */
|
||||
int nfmt;
|
||||
Convfmt fmt[Maxfmt];
|
||||
} fmtalloc;
|
||||
|
||||
static Convfmt knownfmt[] = {
|
||||
' ', _flagfmt,
|
||||
'#', _flagfmt,
|
||||
'%', _percentfmt,
|
||||
'+', _flagfmt,
|
||||
',', _flagfmt,
|
||||
'-', _flagfmt,
|
||||
'C', _runefmt,
|
||||
'E', _efgfmt,
|
||||
'G', _efgfmt,
|
||||
'S', _runesfmt,
|
||||
'X', _ifmt,
|
||||
'b', _ifmt,
|
||||
'c', _charfmt,
|
||||
'd', _ifmt,
|
||||
'e', _efgfmt,
|
||||
'f', _efgfmt,
|
||||
'g', _efgfmt,
|
||||
'h', _flagfmt,
|
||||
'l', _flagfmt,
|
||||
'n', _countfmt,
|
||||
'o', _ifmt,
|
||||
'p', _ifmt,
|
||||
/* 'r', errfmt, */
|
||||
's', _strfmt,
|
||||
'u', _flagfmt,
|
||||
'x', _ifmt,
|
||||
0, nil,
|
||||
};
|
||||
|
||||
int (*doquote)(int);
|
||||
|
||||
/*
|
||||
* _fmtlock() must be set
|
||||
*/
|
||||
static int
|
||||
_fmtinstall(int c, Fmts f)
|
||||
{
|
||||
Convfmt *p, *ep;
|
||||
|
||||
if(c<=0 || c>=65536)
|
||||
return -1;
|
||||
if(!f)
|
||||
f = _badfmt;
|
||||
|
||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
||||
for(p=fmtalloc.fmt; p<ep; p++)
|
||||
if(p->c == c)
|
||||
break;
|
||||
|
||||
if(p == &fmtalloc.fmt[Maxfmt])
|
||||
return -1;
|
||||
|
||||
p->fmt = f;
|
||||
if(p == ep){ /* installing a new format character */
|
||||
fmtalloc.nfmt++;
|
||||
p->c = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fmtinstall(int c, Fmts f)
|
||||
{
|
||||
int ret;
|
||||
|
||||
_fmtlock();
|
||||
ret = _fmtinstall(c, f);
|
||||
_fmtunlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Fmts
|
||||
fmtfmt(int c)
|
||||
{
|
||||
Convfmt *p, *ep;
|
||||
|
||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
||||
for(p=fmtalloc.fmt; p<ep; p++)
|
||||
if(p->c == c){
|
||||
while(p->fmt == nil) /* loop until value is updated */
|
||||
;
|
||||
return p->fmt;
|
||||
}
|
||||
|
||||
/* is this a predefined format char? */
|
||||
_fmtlock();
|
||||
for(p=knownfmt; p->c; p++)
|
||||
if(p->c == c){
|
||||
_fmtinstall(p->c, p->fmt);
|
||||
_fmtunlock();
|
||||
return p->fmt;
|
||||
}
|
||||
_fmtunlock();
|
||||
|
||||
return _badfmt;
|
||||
}
|
||||
|
||||
void*
|
||||
_fmtdispatch(Fmt *f, void *fmt, int isrunes)
|
||||
{
|
||||
Rune rune, r;
|
||||
int i, n;
|
||||
|
||||
f->flags = 0;
|
||||
f->width = f->prec = 0;
|
||||
|
||||
for(;;){
|
||||
if(isrunes){
|
||||
r = *(Rune*)fmt;
|
||||
fmt = (Rune*)fmt + 1;
|
||||
}else{
|
||||
fmt = (char*)fmt + chartorune(&rune, 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;
|
||||
}
|
||||
}
|
99
libc/fmt.h
Normal file
99
libc/fmt.h
Normal file
@ -0,0 +1,99 @@
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _FMTH_
|
||||
#define _FMTH_ 1
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef _UTFH_
|
||||
#include <utf.h>
|
||||
#endif
|
||||
|
||||
typedef struct Fmt Fmt;
|
||||
struct Fmt{
|
||||
unsigned char runes; /* output buffer is runes or chars? */
|
||||
void *start; /* of buffer */
|
||||
void *to; /* current place in the buffer */
|
||||
void *stop; /* end of the buffer; overwritten if flush fails */
|
||||
int (*flush)(Fmt *); /* called when to == stop */
|
||||
void *farg; /* to make flush a closure */
|
||||
int nfmt; /* num chars formatted so far */
|
||||
va_list args; /* args passed to dofmt */
|
||||
int r; /* % format Rune */
|
||||
int width;
|
||||
int prec;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
enum{
|
||||
FmtWidth = 1,
|
||||
FmtLeft = FmtWidth << 1,
|
||||
FmtPrec = FmtLeft << 1,
|
||||
FmtSharp = FmtPrec << 1,
|
||||
FmtSpace = FmtSharp << 1,
|
||||
FmtSign = FmtSpace << 1,
|
||||
FmtZero = FmtSign << 1,
|
||||
FmtUnsigned = FmtZero << 1,
|
||||
FmtShort = FmtUnsigned << 1,
|
||||
FmtLong = FmtShort << 1,
|
||||
FmtVLong = FmtLong << 1,
|
||||
FmtComma = FmtVLong << 1,
|
||||
FmtByte = FmtComma << 1,
|
||||
FmtLDouble = FmtByte << 1,
|
||||
|
||||
FmtFlag = FmtLDouble << 1
|
||||
};
|
||||
|
||||
extern int print(char*, ...);
|
||||
extern char* seprint(char*, char*, char*, ...);
|
||||
extern char* vseprint(char*, char*, char*, va_list);
|
||||
extern int snprint(char*, int, char*, ...);
|
||||
extern int vsnprint(char*, int, char*, va_list);
|
||||
extern char* smprint(char*, ...);
|
||||
extern char* vsmprint(char*, va_list);
|
||||
extern int sprint(char*, char*, ...);
|
||||
extern int fprint(int, char*, ...);
|
||||
extern int vfprint(int, char*, va_list);
|
||||
|
||||
extern int runesprint(Rune*, char*, ...);
|
||||
extern int runesnprint(Rune*, int, char*, ...);
|
||||
extern int runevsnprint(Rune*, int, char*, va_list);
|
||||
extern Rune* runeseprint(Rune*, Rune*, char*, ...);
|
||||
extern Rune* runevseprint(Rune*, Rune*, char*, va_list);
|
||||
extern Rune* runesmprint(char*, ...);
|
||||
extern Rune* runevsmprint(char*, va_list);
|
||||
|
||||
extern int fmtfdinit(Fmt*, int, char*, int);
|
||||
extern int fmtfdflush(Fmt*);
|
||||
extern int fmtstrinit(Fmt*);
|
||||
extern char* fmtstrflush(Fmt*);
|
||||
|
||||
extern int quotestrfmt(Fmt *f);
|
||||
extern void quotefmtinstall(void);
|
||||
extern int (*fmtdoquote)(int);
|
||||
|
||||
|
||||
extern int fmtinstall(int, int (*)(Fmt*));
|
||||
extern int dofmt(Fmt*, char*);
|
||||
extern int fmtprint(Fmt*, char*, ...);
|
||||
extern int fmtvprint(Fmt*, char*, va_list);
|
||||
extern int fmtrune(Fmt*, int);
|
||||
extern int fmtstrcpy(Fmt*, char*);
|
||||
|
||||
extern double fmtstrtod(const char *, char **);
|
||||
extern double fmtcharstod(int(*)(void*), void*);
|
||||
|
||||
#endif
|
85
libc/fmtdef.h
Normal file
85
libc/fmtdef.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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)
|
31
libc/fmtfd.c
Normal file
31
libc/fmtfd.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/*
|
||||
* public routine for final flush of a formatting buffer
|
||||
* to a file descriptor; returns total char count.
|
||||
*/
|
||||
int
|
||||
fmtfdflush(Fmt *f)
|
||||
{
|
||||
if(_fmtFdFlush(f) <= 0)
|
||||
return -1;
|
||||
return f->nfmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize an output buffer for buffered printing
|
||||
*/
|
||||
int
|
||||
fmtfdinit(Fmt *f, int fd, char *buf, int size)
|
||||
{
|
||||
f->runes = 0;
|
||||
f->start = buf;
|
||||
f->to = buf;
|
||||
f->stop = buf + size;
|
||||
f->flush = _fmtFdFlush;
|
||||
f->farg = (void*)fd;
|
||||
f->nfmt = 0;
|
||||
return 0;
|
||||
}
|
16
libc/fmtlock.c
Normal file
16
libc/fmtlock.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static Lock fmtl;
|
||||
|
||||
void
|
||||
_fmtlock(void)
|
||||
{
|
||||
lock(&fmtl);
|
||||
}
|
||||
|
||||
void
|
||||
_fmtunlock(void)
|
||||
{
|
||||
unlock(&fmtl);
|
||||
}
|
32
libc/fmtprint.c
Normal file
32
libc/fmtprint.c
Normal file
@ -0,0 +1,32 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
|
||||
/*
|
||||
* format a string into the output buffer
|
||||
* designed for formats which themselves call fmt,
|
||||
* but ignore any width flags
|
||||
*/
|
||||
int
|
||||
fmtprint(Fmt *f, char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
int n;
|
||||
|
||||
f->flags = 0;
|
||||
f->width = 0;
|
||||
f->prec = 0;
|
||||
va = 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;
|
||||
}
|
||||
|
247
libc/fmtquote.c
Normal file
247
libc/fmtquote.c
Normal file
@ -0,0 +1,247 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/*
|
||||
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
|
||||
* How many runes? How much of the input will be consumed?
|
||||
* The parameter q is filled in by _quotesetup.
|
||||
* The string may be UTF or Runes (s or r).
|
||||
* Return count does not include NUL.
|
||||
* Terminate the scan at the first of:
|
||||
* NUL in input
|
||||
* count exceeded in input
|
||||
* count exceeded on output
|
||||
* *ninp is set to number of input bytes accepted.
|
||||
* nin may be <0 initially, to avoid checking input by count.
|
||||
*/
|
||||
void
|
||||
_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
|
||||
{
|
||||
int w;
|
||||
Rune c;
|
||||
|
||||
q->quoted = 0;
|
||||
q->nbytesout = 0;
|
||||
q->nrunesout = 0;
|
||||
q->nbytesin = 0;
|
||||
q->nrunesin = 0;
|
||||
if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
|
||||
if(nout < 2)
|
||||
return;
|
||||
q->quoted = 1;
|
||||
q->nbytesout = 2;
|
||||
q->nrunesout = 2;
|
||||
}
|
||||
for(; nin!=0; nin-=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 = *(uchar*)rm++;
|
||||
}
|
||||
if(f->runes){
|
||||
FMTRCHAR(f, rt, rs, r);
|
||||
if(r == '\'')
|
||||
FMTRCHAR(f, rt, rs, r);
|
||||
}else{
|
||||
FMTRUNE(f, t, s, r);
|
||||
if(r == '\'')
|
||||
FMTRUNE(f, t, s, r);
|
||||
}
|
||||
}
|
||||
|
||||
if(f->runes){
|
||||
FMTRCHAR(f, rt, rs, '\'');
|
||||
USED(rs);
|
||||
f->nfmt += rt - (Rune *)f->to;
|
||||
f->to = rt;
|
||||
if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
|
||||
return -1;
|
||||
}else{
|
||||
FMTRUNE(f, t, s, '\'');
|
||||
USED(s);
|
||||
f->nfmt += t - (char *)f->to;
|
||||
f->to = t;
|
||||
if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_quotestrfmt(int runesin, Fmt *f)
|
||||
{
|
||||
int outlen;
|
||||
Rune *r;
|
||||
char *s;
|
||||
Quoteinfo q;
|
||||
|
||||
f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
|
||||
if(runesin){
|
||||
r = va_arg(f->args, Rune *);
|
||||
s = nil;
|
||||
}else{
|
||||
s = va_arg(f->args, char *);
|
||||
r = nil;
|
||||
}
|
||||
if(!s && !r)
|
||||
return _fmtcpy(f, "<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;
|
||||
}
|
25
libc/fmtrune.c
Normal file
25
libc/fmtrune.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
int
|
||||
fmtrune(Fmt *f, int r)
|
||||
{
|
||||
Rune *rt;
|
||||
char *t;
|
||||
int n;
|
||||
|
||||
if(f->runes){
|
||||
rt = 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;
|
||||
}
|
11
libc/fmtstr.c
Normal file
11
libc/fmtstr.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
fmtstrflush(Fmt *f)
|
||||
{
|
||||
if(f->start == nil)
|
||||
return nil;
|
||||
*(char*)f->to = '\0';
|
||||
return f->start;
|
||||
}
|
31
libc/fmtvprint.c
Normal file
31
libc/fmtvprint.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
|
||||
/*
|
||||
* format a string into the output buffer
|
||||
* designed for formats which themselves call fmt,
|
||||
* but ignore any width flags
|
||||
*/
|
||||
int
|
||||
fmtvprint(Fmt *f, char *fmt, va_list args)
|
||||
{
|
||||
va_list va;
|
||||
int n;
|
||||
|
||||
f->flags = 0;
|
||||
f->width = 0;
|
||||
f->prec = 0;
|
||||
va = 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;
|
||||
}
|
||||
|
14
libc/fprint.c
Normal file
14
libc/fprint.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
17
libc/frand.c
Normal file
17
libc/frand.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define MASK 0x7fffffffL
|
||||
#define NORM (1.0/(1.0+MASK))
|
||||
|
||||
double
|
||||
frand(void)
|
||||
{
|
||||
double x;
|
||||
|
||||
do {
|
||||
x = lrand() * NORM;
|
||||
x = (x + lrand()) * NORM;
|
||||
} while(x >= 1);
|
||||
return x;
|
||||
}
|
37
libc/getfields.c
Normal file
37
libc/getfields.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
17
libc/getpid.c
Normal file
17
libc/getpid.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
getpid(void)
|
||||
{
|
||||
char b[20];
|
||||
int f;
|
||||
|
||||
memset(b, 0, sizeof(b));
|
||||
f = open("#c/pid", 0);
|
||||
if(f >= 0) {
|
||||
read(f, b, sizeof(b));
|
||||
close(f);
|
||||
}
|
||||
return atol(b);
|
||||
}
|
18
libc/lnrand.c
Normal file
18
libc/lnrand.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define MASK 0x7fffffffL
|
||||
|
||||
long
|
||||
lnrand(long n)
|
||||
{
|
||||
long slop, v;
|
||||
|
||||
if(n < 0)
|
||||
return n;
|
||||
slop = MASK % n;
|
||||
do
|
||||
v = lrand();
|
||||
while(v <= slop);
|
||||
return v % n;
|
||||
}
|
64
libc/lock.c
Normal file
64
libc/lock.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
canlock(Lock *lk)
|
||||
{
|
||||
return !tas(&lk->key);
|
||||
}
|
||||
|
||||
void
|
||||
lock(Lock *lk)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* easy case */
|
||||
if(canlock(lk))
|
||||
return;
|
||||
|
||||
/* for multi processor machines */
|
||||
for(i=0; i<100; i++)
|
||||
if(canlock(lk))
|
||||
return;
|
||||
|
||||
for(i=0; i<100; i++) {
|
||||
osyield(0);
|
||||
if(canlock(lk))
|
||||
return;
|
||||
}
|
||||
|
||||
/* looking bad - make sure it is not a priority problem */
|
||||
for(i=0; i<12; i++) {
|
||||
osmsleep(1<<i);
|
||||
if(canlock(lk))
|
||||
return;
|
||||
}
|
||||
|
||||
/* we are in trouble */
|
||||
for(;;) {
|
||||
if(canlock(lk))
|
||||
return;
|
||||
iprint("lock loop %ld: val=%d &lock=%ux pc=%ux\n", getpid(), lk->key, lk, getcallerpc(&lk));
|
||||
osmsleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unlock(Lock *lk)
|
||||
{
|
||||
assert(lk->key);
|
||||
lk->key = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ilock(Lock *lk)
|
||||
{
|
||||
lock(lk);
|
||||
}
|
||||
|
||||
void
|
||||
iunlock(Lock *lk)
|
||||
{
|
||||
unlock(lk);
|
||||
}
|
||||
|
83
libc/lrand.c
Normal file
83
libc/lrand.c
Normal file
@ -0,0 +1,83 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* algorithm by
|
||||
* D. P. Mitchell & J. A. Reeds
|
||||
*/
|
||||
|
||||
#define LEN 607
|
||||
#define TAP 273
|
||||
#define MASK 0x7fffffffL
|
||||
#define A 48271
|
||||
#define M 2147483647
|
||||
#define Q 44488
|
||||
#define R 3399
|
||||
#define NORM (1.0/(1.0+MASK))
|
||||
|
||||
static ulong rng_vec[LEN];
|
||||
static ulong* rng_tap = rng_vec;
|
||||
static ulong* rng_feed = 0;
|
||||
static Lock lk;
|
||||
|
||||
static void
|
||||
isrand(long seed)
|
||||
{
|
||||
long lo, hi, x;
|
||||
int i;
|
||||
|
||||
rng_tap = rng_vec;
|
||||
rng_feed = rng_vec+LEN-TAP;
|
||||
seed = seed%M;
|
||||
if(seed < 0)
|
||||
seed += M;
|
||||
if(seed == 0)
|
||||
seed = 89482311;
|
||||
x = seed;
|
||||
/*
|
||||
* Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1)
|
||||
*/
|
||||
for(i = -20; i < LEN; i++) {
|
||||
hi = x / Q;
|
||||
lo = x % Q;
|
||||
x = A*lo - R*hi;
|
||||
if(x < 0)
|
||||
x += M;
|
||||
if(i >= 0)
|
||||
rng_vec[i] = x;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
srand(long seed)
|
||||
{
|
||||
lock(&lk);
|
||||
isrand(seed);
|
||||
unlock(&lk);
|
||||
}
|
||||
|
||||
long
|
||||
lrand(void)
|
||||
{
|
||||
ulong x;
|
||||
|
||||
lock(&lk);
|
||||
|
||||
rng_tap--;
|
||||
if(rng_tap < rng_vec) {
|
||||
if(rng_feed == 0) {
|
||||
isrand(1);
|
||||
rng_tap--;
|
||||
}
|
||||
rng_tap += LEN;
|
||||
}
|
||||
rng_feed--;
|
||||
if(rng_feed < rng_vec)
|
||||
rng_feed += LEN;
|
||||
x = (*rng_feed + *rng_tap) & MASK;
|
||||
*rng_feed = x;
|
||||
|
||||
unlock(&lk);
|
||||
|
||||
return x;
|
||||
}
|
13
libc/mallocz.c
Normal file
13
libc/mallocz.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void*
|
||||
mallocz(ulong n, int clr)
|
||||
{
|
||||
void *v;
|
||||
|
||||
v = malloc(n);
|
||||
if(v && clr)
|
||||
memset(v, 0, n);
|
||||
return v;
|
||||
}
|
90
libc/mkfile
Normal file
90
libc/mkfile
Normal file
@ -0,0 +1,90 @@
|
||||
<$DSRC/mkfile-$CONF
|
||||
TARG=libc.$L
|
||||
|
||||
OFILES=\
|
||||
charstod.$O\
|
||||
cleanname.$O\
|
||||
convD2M.$O\
|
||||
convM2D.$O\
|
||||
convM2S.$O\
|
||||
convS2M.$O\
|
||||
crypt.$O\
|
||||
dial.$O\
|
||||
dirfstat.$O\
|
||||
dirfwstat.$O\
|
||||
dirmodefmt.$O\
|
||||
dirstat.$O\
|
||||
dirwstat.$O\
|
||||
dofmt.$O\
|
||||
dorfmt.$O\
|
||||
fcallfmt.$O\
|
||||
fltfmt.$O\
|
||||
fmt.$O\
|
||||
fmtfd.$O\
|
||||
fmtlock.$O\
|
||||
fmtprint.$O\
|
||||
fmtquote.$O\
|
||||
fmtrune.$O\
|
||||
fmtstr.$O\
|
||||
fmtvprint.$O\
|
||||
fprint.$O\
|
||||
frand.$O\
|
||||
getfields.$O\
|
||||
getpid.$O\
|
||||
lnrand.$O\
|
||||
lock.$O\
|
||||
lrand.$O\
|
||||
mallocz.$O\
|
||||
nan64.$O\
|
||||
netmkaddr.$O\
|
||||
nrand.$O\
|
||||
nsec.$O\
|
||||
pow10.$O\
|
||||
pushssl.$O\
|
||||
read9pmsg.$O\
|
||||
readn.$O\
|
||||
rune.$O\
|
||||
runefmtstr.$O\
|
||||
runeseprint.$O\
|
||||
runesmprint.$O\
|
||||
runesnprint.$O\
|
||||
runesprint.$O\
|
||||
runetype.$O\
|
||||
runevseprint.$O\
|
||||
runevsmprint.$O\
|
||||
runevsnprint.$O\
|
||||
seprint.$O\
|
||||
smprint.$O\
|
||||
snprint.$O\
|
||||
sprint.$O\
|
||||
strecpy.$O\
|
||||
strtod.$O\
|
||||
strtoll.$O\
|
||||
sysfatal.$O\
|
||||
time.$O\
|
||||
tokenize.$O\
|
||||
truerand.$O\
|
||||
u16.$O\
|
||||
u32.$O\
|
||||
u64.$O\
|
||||
utfecpy.$O\
|
||||
utflen.$O\
|
||||
utfnlen.$O\
|
||||
utfrrune.$O\
|
||||
utfrune.$O\
|
||||
utfutf.$O\
|
||||
vfprint.$O\
|
||||
vseprint.$O\
|
||||
vsmprint.$O\
|
||||
vsnprint.$O
|
||||
|
||||
HFILES=../include/libc.h\
|
||||
fmt.h\
|
||||
fmtdef.h\
|
||||
nan.h\
|
||||
strtod.h\
|
||||
utf.h\
|
||||
utfdef.h
|
||||
|
||||
<$DSRC/mklib-$CONF
|
||||
|
4
libc/nan.h
Normal file
4
libc/nan.h
Normal file
@ -0,0 +1,4 @@
|
||||
extern double __NaN(void);
|
||||
extern double __Inf(int);
|
||||
extern int __isNaN(double);
|
||||
extern int __isInf(double, int);
|
55
libc/nan64.c
Normal file
55
libc/nan64.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 64-bit IEEE not-a-number routines.
|
||||
* This is big/little-endian portable assuming that
|
||||
* the 64-bit doubles and 64-bit integers have the
|
||||
* same byte ordering.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "nan.h"
|
||||
|
||||
// typedef unsigned long long uvlong;
|
||||
// typedef unsigned long ulong;
|
||||
|
||||
static uvlong uvnan = 0x7FF0000000000001;
|
||||
static uvlong uvinf = 0x7FF0000000000000;
|
||||
static uvlong uvneginf = 0xFFF0000000000000;
|
||||
|
||||
double
|
||||
__NaN(void)
|
||||
{
|
||||
return *(double*)&uvnan;
|
||||
}
|
||||
|
||||
int
|
||||
__isNaN(double d)
|
||||
{
|
||||
uvlong x = *(uvlong*)&d;
|
||||
return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
|
||||
}
|
||||
|
||||
double
|
||||
__Inf(int sign)
|
||||
{
|
||||
if(sign < 0)
|
||||
return *(double*)&uvinf;
|
||||
else
|
||||
return *(double*)&uvneginf;
|
||||
}
|
||||
|
||||
int
|
||||
__isInf(double d, int sign)
|
||||
{
|
||||
uvlong x;
|
||||
|
||||
x = *(uvlong*)&d;
|
||||
if(sign == 0)
|
||||
return x==uvinf || x==uvneginf;
|
||||
else if(sign > 0)
|
||||
return x==uvinf;
|
||||
else
|
||||
return x==uvneginf;
|
||||
}
|
||||
|
||||
|
52
libc/netmkaddr.c
Normal file
52
libc/netmkaddr.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* make an address, add the defaults
|
||||
*/
|
||||
char *
|
||||
netmkaddr(char *linear, char *defnet, char *defsrv)
|
||||
{
|
||||
static char addr[256];
|
||||
char *cp;
|
||||
|
||||
/*
|
||||
* dump network name
|
||||
*/
|
||||
cp = strchr(linear, '!');
|
||||
if(cp == 0){
|
||||
if(defnet==0){
|
||||
if(defsrv)
|
||||
snprint(addr, sizeof(addr), "net!%s!%s",
|
||||
linear, defsrv);
|
||||
else
|
||||
snprint(addr, sizeof(addr), "net!%s", linear);
|
||||
}
|
||||
else {
|
||||
if(defsrv)
|
||||
snprint(addr, sizeof(addr), "%s!%s!%s", defnet,
|
||||
linear, defsrv);
|
||||
else
|
||||
snprint(addr, sizeof(addr), "%s!%s", defnet,
|
||||
linear);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* if there is already a service, use it
|
||||
*/
|
||||
cp = strchr(cp+1, '!');
|
||||
if(cp)
|
||||
return linear;
|
||||
|
||||
/*
|
||||
* add default service
|
||||
*/
|
||||
if(defsrv == 0)
|
||||
return linear;
|
||||
snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
|
||||
|
||||
return addr;
|
||||
}
|
18
libc/nrand.c
Normal file
18
libc/nrand.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define MASK 0x7fffffffL
|
||||
|
||||
int
|
||||
nrand(int n)
|
||||
{
|
||||
long slop, v;
|
||||
|
||||
if(n < 0)
|
||||
return n;
|
||||
slop = MASK % n;
|
||||
do
|
||||
v = lrand();
|
||||
while(v <= slop);
|
||||
return v % n;
|
||||
}
|
66
libc/nsec.c
Normal file
66
libc/nsec.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
|
||||
static uvlong order = (uvlong) 0x0001020304050607;
|
||||
|
||||
static void
|
||||
be2vlong(vlong *to, uchar *f)
|
||||
{
|
||||
uchar *t, *o;
|
||||
int i;
|
||||
|
||||
t = (uchar*)to;
|
||||
o = (uchar*)ℴ
|
||||
for(i = 0; i < 8; i++)
|
||||
t[o[i]] = f[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* After a fork with fd's copied, both fd's are pointing to
|
||||
* the same Chan structure. Since the offset is kept in the Chan
|
||||
* structure, the seek's and read's in the two processes can
|
||||
* compete at moving the offset around. Hence the retry loop.
|
||||
*
|
||||
* Since the bintime version doesn't need a seek, it doesn't
|
||||
* have the loop.
|
||||
*/
|
||||
vlong
|
||||
nsec(void)
|
||||
{
|
||||
char b[12+1];
|
||||
static int f = -1;
|
||||
static int usebintime;
|
||||
int retries;
|
||||
vlong t;
|
||||
|
||||
if(f < 0){
|
||||
usebintime = 1;
|
||||
f = open("/dev/bintime", OREAD|OCEXEC);
|
||||
if(f < 0){
|
||||
usebintime = 0;
|
||||
f = open("/dev/nsec", OREAD|OCEXEC);
|
||||
if(f < 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(usebintime){
|
||||
if(read(f, b, sizeof(uvlong)) < 0)
|
||||
goto error;
|
||||
be2vlong(&t, (uchar*)b);
|
||||
return t;
|
||||
} else {
|
||||
for(retries = 0; retries < 100; retries++){
|
||||
if(seek(f, 0, 0) >= 0 && read(f, b, sizeof(b)-1) >= 0){
|
||||
b[sizeof(b)-1] = 0;
|
||||
return strtoll(b, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
close(f);
|
||||
f = -1;
|
||||
return 0;
|
||||
}
|
49
libc/pow10.c
Normal file
49
libc/pow10.c
Normal file
@ -0,0 +1,49 @@
|
||||
#include <u.h>
|
||||
#include <libc.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,
|
||||
1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79,
|
||||
1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89,
|
||||
1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99,
|
||||
1.0e100,1.0e101,1.0e102,1.0e103,1.0e104,1.0e105,1.0e106,1.0e107,1.0e108,1.0e109,
|
||||
1.0e110,1.0e111,1.0e112,1.0e113,1.0e114,1.0e115,1.0e116,1.0e117,1.0e118,1.0e119,
|
||||
1.0e120,1.0e121,1.0e122,1.0e123,1.0e124,1.0e125,1.0e126,1.0e127,1.0e128,1.0e129,
|
||||
1.0e130,1.0e131,1.0e132,1.0e133,1.0e134,1.0e135,1.0e136,1.0e137,1.0e138,1.0e139,
|
||||
1.0e140,1.0e141,1.0e142,1.0e143,1.0e144,1.0e145,1.0e146,1.0e147,1.0e148,1.0e149,
|
||||
1.0e150,1.0e151,1.0e152,1.0e153,1.0e154,1.0e155,1.0e156,1.0e157,1.0e158,1.0e159,
|
||||
};
|
||||
|
||||
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 1/(pow10(m) * pow10(n-m));
|
||||
}
|
||||
if(n < sizeof(tab)/sizeof(tab[0]))
|
||||
return tab[n];
|
||||
m = n/2;
|
||||
return pow10(m) * pow10(n-m);
|
||||
}
|
14
libc/print.c
Normal file
14
libc/print.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
print(char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = vfprint(1, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
44
libc/pushssl.c
Normal file
44
libc/pushssl.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* Since the SSL device uses decimal file descriptors to name channels,
|
||||
* it is impossible for a user-level file server to stand in for the kernel device.
|
||||
* Thus we hard-code #D rather than use /net/ssl.
|
||||
*/
|
||||
|
||||
int
|
||||
pushssl(int fd, char *alg, char *secin, char *secout, int *cfd)
|
||||
{
|
||||
char buf[8];
|
||||
char dname[64];
|
||||
int n, data, ctl;
|
||||
|
||||
ctl = open("#D/ssl/clone", ORDWR);
|
||||
if(ctl < 0)
|
||||
return -1;
|
||||
n = read(ctl, buf, sizeof(buf)-1);
|
||||
if(n < 0)
|
||||
goto error;
|
||||
buf[n] = 0;
|
||||
sprint(dname, "#D/ssl/%s/data", buf);
|
||||
data = open(dname, ORDWR);
|
||||
if(data < 0)
|
||||
goto error;
|
||||
if(fprint(ctl, "fd %d", fd) < 0 ||
|
||||
fprint(ctl, "secretin %s", secin) < 0 ||
|
||||
fprint(ctl, "secretout %s", secout) < 0 ||
|
||||
fprint(ctl, "alg %s", alg) < 0){
|
||||
close(data);
|
||||
goto error;
|
||||
}
|
||||
close(fd);
|
||||
if(cfd != 0)
|
||||
*cfd = ctl;
|
||||
else
|
||||
close(ctl);
|
||||
return data;
|
||||
error:
|
||||
close(ctl);
|
||||
return -1;
|
||||
}
|
8
libc/rand.c
Normal file
8
libc/rand.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
rand(void)
|
||||
{
|
||||
return lrand() & 0x7fff;
|
||||
}
|
31
libc/read9pmsg.c
Normal file
31
libc/read9pmsg.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
read9pmsg(int fd, void *abuf, uint n)
|
||||
{
|
||||
int m, len;
|
||||
uchar *buf;
|
||||
|
||||
buf = abuf;
|
||||
|
||||
/* read count */
|
||||
m = readn(fd, buf, BIT32SZ);
|
||||
if(m != BIT32SZ){
|
||||
if(m < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = GBIT32(buf);
|
||||
if(len <= BIT32SZ || len > n){
|
||||
werrstr("bad length in 9P2000 message header");
|
||||
return -1;
|
||||
}
|
||||
len -= BIT32SZ;
|
||||
m = readn(fd, buf+BIT32SZ, len);
|
||||
if(m < len)
|
||||
return 0;
|
||||
return BIT32SZ+m;
|
||||
}
|
22
libc/readn.c
Normal file
22
libc/readn.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
162
libc/rune.c
Normal file
162
libc/rune.c
Normal file
@ -0,0 +1,162 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
enum
|
||||
{
|
||||
Bit1 = 7,
|
||||
Bitx = 6,
|
||||
Bit2 = 5,
|
||||
Bit3 = 4,
|
||||
Bit4 = 3,
|
||||
|
||||
T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
|
||||
Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
|
||||
T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
|
||||
T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
|
||||
T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
|
||||
|
||||
Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
|
||||
Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
|
||||
Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
|
||||
|
||||
Maskx = (1<<Bitx)-1, /* 0011 1111 */
|
||||
Testx = Maskx ^ 0xFF, /* 1100 0000 */
|
||||
|
||||
Bad = Runeerror,
|
||||
};
|
||||
|
||||
int
|
||||
chartorune(Rune *rune, char *str)
|
||||
{
|
||||
int c, c1, c2;
|
||||
long l;
|
||||
|
||||
/*
|
||||
* one character sequence
|
||||
* 00000-0007F => T1
|
||||
*/
|
||||
c = *(uchar*)str;
|
||||
if(c < Tx) {
|
||||
*rune = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* two character sequence
|
||||
* 0080-07FF => T2 Tx
|
||||
*/
|
||||
c1 = *(uchar*)(str+1) ^ Tx;
|
||||
if(c1 & Testx)
|
||||
goto bad;
|
||||
if(c < T3) {
|
||||
if(c < T2)
|
||||
goto bad;
|
||||
l = ((c << Bitx) | c1) & Rune2;
|
||||
if(l <= Rune1)
|
||||
goto bad;
|
||||
*rune = l;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* three character sequence
|
||||
* 0800-FFFF => T3 Tx Tx
|
||||
*/
|
||||
c2 = *(uchar*)(str+2) ^ Tx;
|
||||
if(c2 & Testx)
|
||||
goto bad;
|
||||
if(c < T4) {
|
||||
l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
|
||||
if(l <= Rune2)
|
||||
goto bad;
|
||||
*rune = l;
|
||||
return 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* bad decoding
|
||||
*/
|
||||
bad:
|
||||
*rune = Bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
runetochar(char *str, Rune *rune)
|
||||
{
|
||||
long c;
|
||||
|
||||
/*
|
||||
* one character sequence
|
||||
* 00000-0007F => 00-7F
|
||||
*/
|
||||
c = *rune;
|
||||
if(c <= Rune1) {
|
||||
str[0] = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* two character sequence
|
||||
* 0080-07FF => T2 Tx
|
||||
*/
|
||||
if(c <= Rune2) {
|
||||
str[0] = T2 | (c >> 1*Bitx);
|
||||
str[1] = Tx | (c & Maskx);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* three character sequence
|
||||
* 0800-FFFF => T3 Tx Tx
|
||||
*/
|
||||
str[0] = T3 | (c >> 2*Bitx);
|
||||
str[1] = Tx | ((c >> 1*Bitx) & Maskx);
|
||||
str[2] = Tx | (c & Maskx);
|
||||
return 3;
|
||||
}
|
||||
|
||||
int
|
||||
runelen(long c)
|
||||
{
|
||||
Rune rune;
|
||||
char str[10];
|
||||
|
||||
rune = c;
|
||||
return runetochar(str, &rune);
|
||||
}
|
||||
|
||||
int
|
||||
runenlen(Rune *r, int nrune)
|
||||
{
|
||||
int nb, c;
|
||||
|
||||
nb = 0;
|
||||
while(nrune--) {
|
||||
c = *r++;
|
||||
if(c <= Rune1)
|
||||
nb++;
|
||||
else
|
||||
if(c <= Rune2)
|
||||
nb += 2;
|
||||
else
|
||||
nb += 3;
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
int
|
||||
fullrune(char *str, int n)
|
||||
{
|
||||
int c;
|
||||
|
||||
if(n > 0) {
|
||||
c = *(uchar*)str;
|
||||
if(c < Tx)
|
||||
return 1;
|
||||
if(n > 1)
|
||||
if(c < T3 || n > 2)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
11
libc/runefmtstr.c
Normal file
11
libc/runefmtstr.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runefmtstrflush(Fmt *f)
|
||||
{
|
||||
if(f->start == nil)
|
||||
return nil;
|
||||
*(Rune*)f->to = '\0';
|
||||
return f->start;
|
||||
}
|
14
libc/runeseprint.c
Normal file
14
libc/runeseprint.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runeseprint(Rune *buf, Rune *e, char *fmt, ...)
|
||||
{
|
||||
Rune *p;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = runevseprint(buf, e, fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
14
libc/runesmprint.c
Normal file
14
libc/runesmprint.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runesmprint(char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
Rune *p;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = runevsmprint(fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
15
libc/runesnprint.c
Normal file
15
libc/runesnprint.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runesnprint(Rune *buf, int len, char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = runevsnprint(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
||||
|
14
libc/runesprint.c
Normal file
14
libc/runesprint.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runesprint(Rune *buf, char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = runevsnprint(buf, 256, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
10
libc/runestrcat.c
Normal file
10
libc/runestrcat.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrcat(Rune *s1, Rune *s2)
|
||||
{
|
||||
|
||||
runestrcpy(runestrchr(s1, 0), s2);
|
||||
return s1;
|
||||
}
|
20
libc/runestrchr.c
Normal file
20
libc/runestrchr.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrchr(Rune *s, Rune c)
|
||||
{
|
||||
Rune c0 = c;
|
||||
Rune c1;
|
||||
|
||||
if(c == 0) {
|
||||
while(*s++)
|
||||
;
|
||||
return s-1;
|
||||
}
|
||||
|
||||
while(c1 = *s++)
|
||||
if(c1 == c0)
|
||||
return s-1;
|
||||
return 0;
|
||||
}
|
20
libc/runestrcmp.c
Normal file
20
libc/runestrcmp.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runestrcmp(Rune *s1, Rune *s2)
|
||||
{
|
||||
Rune c1, c2;
|
||||
|
||||
for(;;) {
|
||||
c1 = *s1++;
|
||||
c2 = *s2++;
|
||||
if(c1 != c2) {
|
||||
if(c1 > c2)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
if(c1 == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
13
libc/runestrcpy.c
Normal file
13
libc/runestrcpy.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrcpy(Rune *s1, Rune *s2)
|
||||
{
|
||||
Rune *os1;
|
||||
|
||||
os1 = s1;
|
||||
while(*s1++ = *s2++)
|
||||
;
|
||||
return os1;
|
||||
}
|
14
libc/runestrdup.c
Normal file
14
libc/runestrdup.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrdup(Rune *s)
|
||||
{
|
||||
Rune *ns;
|
||||
|
||||
ns = malloc(sizeof(Rune)*(runestrlen(s) + 1));
|
||||
if(ns == 0)
|
||||
return 0;
|
||||
|
||||
return runestrcpy(ns, s);
|
||||
}
|
17
libc/runestrecpy.c
Normal file
17
libc/runestrecpy.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrecpy(Rune *s1, Rune *es1, Rune *s2)
|
||||
{
|
||||
if(s1 >= es1)
|
||||
return s1;
|
||||
|
||||
while(*s1++ = *s2++){
|
||||
if(s1 == es1){
|
||||
*--s1 = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s1;
|
||||
}
|
9
libc/runestrlen.c
Normal file
9
libc/runestrlen.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
long
|
||||
runestrlen(Rune *s)
|
||||
{
|
||||
|
||||
return runestrchr(s, 0) - s;
|
||||
}
|
17
libc/runestrncat.c
Normal file
17
libc/runestrncat.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrncat(Rune *s1, Rune *s2, long n)
|
||||
{
|
||||
Rune *os1;
|
||||
|
||||
os1 = s1;
|
||||
s1 = runestrchr(s1, 0);
|
||||
while(*s1++ = *s2++)
|
||||
if(--n < 0) {
|
||||
s1[-1] = 0;
|
||||
break;
|
||||
}
|
||||
return os1;
|
||||
}
|
22
libc/runestrncmp.c
Normal file
22
libc/runestrncmp.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runestrncmp(Rune *s1, Rune *s2, long n)
|
||||
{
|
||||
Rune c1, c2;
|
||||
|
||||
while(n > 0) {
|
||||
c1 = *s1++;
|
||||
c2 = *s2++;
|
||||
n--;
|
||||
if(c1 != c2) {
|
||||
if(c1 > c2)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
if(c1 == 0)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
18
libc/runestrncpy.c
Normal file
18
libc/runestrncpy.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrncpy(Rune *s1, Rune *s2, long n)
|
||||
{
|
||||
int i;
|
||||
Rune *os1;
|
||||
|
||||
os1 = s1;
|
||||
for(i = 0; i < n; i++)
|
||||
if((*s1++ = *s2++) == 0) {
|
||||
while(++i < n)
|
||||
*s1++ = 0;
|
||||
return os1;
|
||||
}
|
||||
return os1;
|
||||
}
|
15
libc/runestrrchr.c
Normal file
15
libc/runestrrchr.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runestrrchr(Rune *s, Rune c)
|
||||
{
|
||||
Rune *r;
|
||||
|
||||
if(c == 0)
|
||||
return runestrchr(s, 0);
|
||||
r = 0;
|
||||
while(s = runestrchr(s, c))
|
||||
r = s++;
|
||||
return r;
|
||||
}
|
29
libc/runestrstr.c
Normal file
29
libc/runestrstr.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* Return pointer to first occurrence of s2 in s1,
|
||||
* 0 if none
|
||||
*/
|
||||
Rune*
|
||||
runestrstr(Rune *s1, Rune *s2)
|
||||
{
|
||||
Rune *p, *pa, *pb;
|
||||
int c0, c;
|
||||
|
||||
c0 = *s2;
|
||||
if(c0 == 0)
|
||||
return s1;
|
||||
s2++;
|
||||
for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) {
|
||||
pa = p;
|
||||
for(pb=s2;; pb++) {
|
||||
c = *pb;
|
||||
if(c == 0)
|
||||
return p;
|
||||
if(c != *++pa)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
1138
libc/runetype.c
Normal file
1138
libc/runetype.c
Normal file
File diff suppressed because it is too large
Load Diff
23
libc/runevseprint.c
Normal file
23
libc/runevseprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(e <= buf)
|
||||
return nil;
|
||||
f.runes = 1;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = e - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
f.args = args;
|
||||
dofmt(&f, fmt);
|
||||
*(Rune*)f.to = '\0';
|
||||
return f.to;
|
||||
}
|
||||
|
70
libc/runevsmprint.c
Normal file
70
libc/runevsmprint.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
static int
|
||||
runeFmtStrFlush(Fmt *f)
|
||||
{
|
||||
Rune *s;
|
||||
int n;
|
||||
|
||||
if(f->start == nil)
|
||||
return 0;
|
||||
n = (int)f->farg;
|
||||
n *= 2;
|
||||
s = f->start;
|
||||
f->start = realloc(s, sizeof(Rune)*n);
|
||||
if(f->start == nil){
|
||||
f->farg = nil;
|
||||
f->to = nil;
|
||||
f->stop = nil;
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
f->farg = (void*)n;
|
||||
f->to = (Rune*)f->start + ((Rune*)f->to - s);
|
||||
f->stop = (Rune*)f->start + n - 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
runefmtstrinit(Fmt *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
memset(f, 0, sizeof *f);
|
||||
f->runes = 1;
|
||||
n = 32;
|
||||
f->start = malloc(sizeof(Rune)*n);
|
||||
if(f->start == nil)
|
||||
return -1;
|
||||
f->to = f->start;
|
||||
f->stop = (Rune*)f->start + n - 1;
|
||||
f->flush = runeFmtStrFlush;
|
||||
f->farg = (void*)n;
|
||||
f->nfmt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* print into an allocated string buffer
|
||||
*/
|
||||
Rune*
|
||||
runevsmprint(char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
int n;
|
||||
|
||||
if(runefmtstrinit(&f) < 0)
|
||||
return nil;
|
||||
f.args = args;
|
||||
n = dofmt(&f, fmt);
|
||||
if(f.start == nil)
|
||||
return nil;
|
||||
if(n < 0){
|
||||
free(f.start);
|
||||
return nil;
|
||||
}
|
||||
*(Rune*)f.to = '\0';
|
||||
return f.start;
|
||||
}
|
22
libc/runevsnprint.c
Normal file
22
libc/runevsnprint.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
runevsnprint(Rune *buf, int len, char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(len <= 0)
|
||||
return -1;
|
||||
f.runes = 1;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = buf + len - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
f.args = args;
|
||||
dofmt(&f, fmt);
|
||||
*(Rune*)f.to = '\0';
|
||||
return (Rune*)f.to - buf;
|
||||
}
|
14
libc/seprint.c
Normal file
14
libc/seprint.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
14
libc/smprint.c
Normal file
14
libc/smprint.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
smprint(char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *p;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = vsmprint(fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
15
libc/snprint.c
Normal file
15
libc/snprint.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
||||
|
14
libc/sprint.c
Normal file
14
libc/sprint.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
sprint(char *buf, char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = vsnprint(buf, 65536, fmt, args); /* big number, but sprint is deprecated anyway */
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
17
libc/strecpy.c
Normal file
17
libc/strecpy.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
532
libc/strtod.c
Normal file
532
libc/strtod.c
Normal file
@ -0,0 +1,532 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* This routine will convert to arbitrary precision
|
||||
* floating point entirely in multi-precision fixed.
|
||||
* The answer is the closest floating point number to
|
||||
* the given decimal number. Exactly half way are
|
||||
* rounded ala ieee rules.
|
||||
* Method is to scale input decimal between .500 and .999...
|
||||
* with external power of 2, then binary search for the
|
||||
* closest mantissa to this decimal number.
|
||||
* Nmant is is the required precision. (53 for ieee dp)
|
||||
* Nbits is the max number of bits/word. (must be <= 28)
|
||||
* Prec is calculated - the number of words of fixed mantissa.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
Nbits = 28, // bits safely represented in a ulong
|
||||
Nmant = 53, // bits of precision required
|
||||
Bias = 1022,
|
||||
Prec = (Nmant+Nbits+1)/Nbits, // words of Nbits each to represent mantissa
|
||||
Sigbit = 1<<(Prec*Nbits-Nmant), // first significant bit of Prec-th word
|
||||
Ndig = 1500,
|
||||
One = (ulong)(1<<Nbits),
|
||||
Half = (ulong)(One>>1),
|
||||
Maxe = 310,
|
||||
Fsign = 1<<0, // found -
|
||||
Fesign = 1<<1, // found e-
|
||||
Fdpoint = 1<<2, // found .
|
||||
|
||||
S0 = 0, // _ _S0 +S1 #S2 .S3
|
||||
S1, // _+ #S2 .S3
|
||||
S2, // _+# #S2 .S4 eS5
|
||||
S3, // _+. #S4
|
||||
S4, // _+#.# #S4 eS5
|
||||
S5, // _+#.#e +S6 #S7
|
||||
S6, // _+#.#e+ #S7
|
||||
S7, // _+#.#e+# #S7
|
||||
};
|
||||
|
||||
static ulong
|
||||
umuldiv(ulong a, ulong b, ulong c)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = ((double)a * (double)b) / (double)c;
|
||||
if(d >= 4294967295.)
|
||||
d = 4294967295.;
|
||||
return d;
|
||||
}
|
||||
|
||||
static int xcmp(char*, char*);
|
||||
static int fpcmp(char*, ulong*);
|
||||
static void frnorm(ulong*);
|
||||
static void divascii(char*, int*, int*, int*);
|
||||
static void mulascii(char*, int*, int*, int*);
|
||||
static void divby(char*, int*, int);
|
||||
|
||||
typedef struct Tab Tab;
|
||||
struct Tab
|
||||
{
|
||||
int bp;
|
||||
int siz;
|
||||
char* cmp;
|
||||
};
|
||||
|
||||
double
|
||||
strtod(char *as, char **aas)
|
||||
{
|
||||
int na, ona, ex, dp, bp, c, i, flag, state;
|
||||
ulong low[Prec], hig[Prec], mid[Prec], num, den;
|
||||
double d;
|
||||
char *s, a[Ndig];
|
||||
|
||||
flag = 0; // Fsign, Fesign, Fdpoint
|
||||
na = 0; // number of digits of a[]
|
||||
dp = 0; // na of decimal point
|
||||
ex = 0; // exonent
|
||||
|
||||
state = S0;
|
||||
for(s=as;; s++) {
|
||||
c = *s;
|
||||
if(c >= '0' && c <= '9') {
|
||||
switch(state) {
|
||||
case S0:
|
||||
case S1:
|
||||
case S2:
|
||||
state = S2;
|
||||
break;
|
||||
case S3:
|
||||
case S4:
|
||||
state = S4;
|
||||
break;
|
||||
|
||||
case S5:
|
||||
case S6:
|
||||
case S7:
|
||||
state = S7;
|
||||
ex = ex*10 + (c-'0');
|
||||
continue;
|
||||
}
|
||||
if(na == 0 && c == '0') {
|
||||
dp--;
|
||||
continue;
|
||||
}
|
||||
if(na < Ndig-50)
|
||||
a[na++] = c;
|
||||
continue;
|
||||
}
|
||||
switch(c) {
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\v':
|
||||
case '\f':
|
||||
case '\r':
|
||||
case ' ':
|
||||
if(state == S0)
|
||||
continue;
|
||||
break;
|
||||
case '-':
|
||||
if(state == S0)
|
||||
flag |= Fsign;
|
||||
else
|
||||
flag |= Fesign;
|
||||
case '+':
|
||||
if(state == S0)
|
||||
state = S1;
|
||||
else
|
||||
if(state == S5)
|
||||
state = S6;
|
||||
else
|
||||
break; // syntax
|
||||
continue;
|
||||
case '.':
|
||||
flag |= Fdpoint;
|
||||
dp = na;
|
||||
if(state == S0 || state == S1) {
|
||||
state = S3;
|
||||
continue;
|
||||
}
|
||||
if(state == S2) {
|
||||
state = S4;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
if(state == S2 || state == S4) {
|
||||
state = S5;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* clean up return char-pointer
|
||||
*/
|
||||
switch(state) {
|
||||
case S0:
|
||||
if(xcmp(s, "nan") == 0) {
|
||||
if(aas != nil)
|
||||
*aas = s+3;
|
||||
goto retnan;
|
||||
}
|
||||
case S1:
|
||||
if(xcmp(s, "infinity") == 0) {
|
||||
if(aas != nil)
|
||||
*aas = s+8;
|
||||
goto retinf;
|
||||
}
|
||||
if(xcmp(s, "inf") == 0) {
|
||||
if(aas != nil)
|
||||
*aas = s+3;
|
||||
goto retinf;
|
||||
}
|
||||
case S3:
|
||||
if(aas != nil)
|
||||
*aas = as;
|
||||
goto ret0; // no digits found
|
||||
case S6:
|
||||
s--; // back over +-
|
||||
case S5:
|
||||
s--; // back over e
|
||||
break;
|
||||
}
|
||||
if(aas != nil)
|
||||
*aas = s;
|
||||
|
||||
if(flag & Fdpoint)
|
||||
while(na > 0 && a[na-1] == '0')
|
||||
na--;
|
||||
if(na == 0)
|
||||
goto ret0; // zero
|
||||
a[na] = 0;
|
||||
if(!(flag & Fdpoint))
|
||||
dp = na;
|
||||
if(flag & Fesign)
|
||||
ex = -ex;
|
||||
dp += ex;
|
||||
if(dp < -Maxe-Nmant/3) /* actually -Nmant*log(2)/log(10), but Nmant/3 close enough */
|
||||
goto ret0; // underflow by exp
|
||||
else
|
||||
if(dp > +Maxe)
|
||||
goto retinf; // overflow by exp
|
||||
|
||||
/*
|
||||
* normalize the decimal ascii number
|
||||
* to range .[5-9][0-9]* e0
|
||||
*/
|
||||
bp = 0; // binary exponent
|
||||
while(dp > 0)
|
||||
divascii(a, &na, &dp, &bp);
|
||||
while(dp < 0 || a[0] < '5')
|
||||
mulascii(a, &na, &dp, &bp);
|
||||
a[na] = 0;
|
||||
|
||||
/*
|
||||
* very small numbers are represented using
|
||||
* bp = -Bias+1. adjust accordingly.
|
||||
*/
|
||||
if(bp < -Bias+1){
|
||||
ona = na;
|
||||
divby(a, &na, -bp-Bias+1);
|
||||
if(na < ona){
|
||||
memmove(a+ona-na, a, na);
|
||||
memset(a, '0', ona-na);
|
||||
na = ona;
|
||||
}
|
||||
a[na] = 0;
|
||||
bp = -Bias+1;
|
||||
}
|
||||
|
||||
/* close approx by naive conversion */
|
||||
num = 0;
|
||||
den = 1;
|
||||
for(i=0; i<9 && (c=a[i]); i++) {
|
||||
num = num*10 + (c-'0');
|
||||
den *= 10;
|
||||
}
|
||||
low[0] = umuldiv(num, One, den);
|
||||
hig[0] = umuldiv(num+1, One, den);
|
||||
for(i=1; i<Prec; i++) {
|
||||
low[i] = 0;
|
||||
hig[i] = One-1;
|
||||
}
|
||||
|
||||
/* binary search for closest mantissa */
|
||||
for(;;) {
|
||||
/* mid = (hig + low) / 2 */
|
||||
c = 0;
|
||||
for(i=0; i<Prec; i++) {
|
||||
mid[i] = hig[i] + low[i];
|
||||
if(c)
|
||||
mid[i] += One;
|
||||
c = mid[i] & 1;
|
||||
mid[i] >>= 1;
|
||||
}
|
||||
frnorm(mid);
|
||||
|
||||
/* compare */
|
||||
c = fpcmp(a, mid);
|
||||
if(c > 0) {
|
||||
c = 1;
|
||||
for(i=0; i<Prec; i++)
|
||||
if(low[i] != mid[i]) {
|
||||
c = 0;
|
||||
low[i] = mid[i];
|
||||
}
|
||||
if(c)
|
||||
break; // between mid and hig
|
||||
continue;
|
||||
}
|
||||
if(c < 0) {
|
||||
for(i=0; i<Prec; i++)
|
||||
hig[i] = mid[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only hard part is if even/odd roundings wants to go up */
|
||||
c = mid[Prec-1] & (Sigbit-1);
|
||||
if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
|
||||
mid[Prec-1] -= c;
|
||||
break; // exactly mid
|
||||
}
|
||||
|
||||
/* normal rounding applies */
|
||||
c = mid[Prec-1] & (Sigbit-1);
|
||||
mid[Prec-1] -= c;
|
||||
if(c >= Sigbit/2) {
|
||||
mid[Prec-1] += Sigbit;
|
||||
frnorm(mid);
|
||||
}
|
||||
d = 0;
|
||||
for(i=0; i<Prec; i++)
|
||||
d = d*One + mid[i];
|
||||
if(flag & Fsign)
|
||||
d = -d;
|
||||
d = ldexp(d, bp - Prec*Nbits);
|
||||
return d;
|
||||
|
||||
ret0:
|
||||
return 0;
|
||||
|
||||
retnan:
|
||||
return __NaN();
|
||||
|
||||
retinf:
|
||||
if(flag & Fsign)
|
||||
return __Inf(-1);
|
||||
return __Inf(+1);
|
||||
}
|
||||
|
||||
static void
|
||||
frnorm(ulong *f)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
c = 0;
|
||||
for(i=Prec-1; i>0; i--) {
|
||||
f[i] += c;
|
||||
c = f[i] >> Nbits;
|
||||
f[i] &= One-1;
|
||||
}
|
||||
f[0] += c;
|
||||
}
|
||||
|
||||
static int
|
||||
fpcmp(char *a, ulong* f)
|
||||
{
|
||||
ulong tf[Prec];
|
||||
int i, d, c;
|
||||
|
||||
for(i=0; i<Prec; i++)
|
||||
tf[i] = f[i];
|
||||
|
||||
for(;;) {
|
||||
/* tf *= 10 */
|
||||
for(i=0; i<Prec; i++)
|
||||
tf[i] = tf[i]*10;
|
||||
frnorm(tf);
|
||||
d = (tf[0] >> Nbits) + '0';
|
||||
tf[0] &= One-1;
|
||||
|
||||
/* compare next digit */
|
||||
c = *a;
|
||||
if(c == 0) {
|
||||
if('0' < d)
|
||||
return -1;
|
||||
if(tf[0] != 0)
|
||||
goto cont;
|
||||
for(i=1; i<Prec; i++)
|
||||
if(tf[i] != 0)
|
||||
goto cont;
|
||||
return 0;
|
||||
}
|
||||
if(c > d)
|
||||
return +1;
|
||||
if(c < d)
|
||||
return -1;
|
||||
a++;
|
||||
cont:;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_divby(char *a, int *na, int b)
|
||||
{
|
||||
int n, c;
|
||||
char *p;
|
||||
|
||||
p = a;
|
||||
n = 0;
|
||||
while(n>>b == 0) {
|
||||
c = *a++;
|
||||
if(c == 0) {
|
||||
while(n) {
|
||||
c = n*10;
|
||||
if(c>>b)
|
||||
break;
|
||||
n = c;
|
||||
}
|
||||
goto xx;
|
||||
}
|
||||
n = n*10 + c-'0';
|
||||
(*na)--;
|
||||
}
|
||||
for(;;) {
|
||||
c = n>>b;
|
||||
n -= c<<b;
|
||||
*p++ = c + '0';
|
||||
c = *a++;
|
||||
if(c == 0)
|
||||
break;
|
||||
n = n*10 + c-'0';
|
||||
}
|
||||
(*na)++;
|
||||
xx:
|
||||
while(n) {
|
||||
n = n*10;
|
||||
c = n>>b;
|
||||
n -= c<<b;
|
||||
*p++ = c + '0';
|
||||
(*na)++;
|
||||
}
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
divby(char *a, int *na, int b)
|
||||
{
|
||||
while(b > 9){
|
||||
_divby(a, na, 9);
|
||||
a[*na] = 0;
|
||||
b -= 9;
|
||||
}
|
||||
if(b > 0)
|
||||
_divby(a, na, b);
|
||||
}
|
||||
|
||||
static Tab tab1[] =
|
||||
{
|
||||
1, 0, "",
|
||||
3, 1, "7",
|
||||
6, 2, "63",
|
||||
9, 3, "511",
|
||||
13, 4, "8191",
|
||||
16, 5, "65535",
|
||||
19, 6, "524287",
|
||||
23, 7, "8388607",
|
||||
26, 8, "67108863",
|
||||
27, 9, "134217727",
|
||||
};
|
||||
|
||||
static void
|
||||
divascii(char *a, int *na, int *dp, int *bp)
|
||||
{
|
||||
int b, d;
|
||||
Tab *t;
|
||||
|
||||
d = *dp;
|
||||
if(d >= nelem(tab1))
|
||||
d = nelem(tab1)-1;
|
||||
t = tab1 + d;
|
||||
b = t->bp;
|
||||
if(memcmp(a, t->cmp, t->siz) > 0)
|
||||
d--;
|
||||
*dp -= d;
|
||||
*bp += b;
|
||||
divby(a, na, b);
|
||||
}
|
||||
|
||||
static void
|
||||
mulby(char *a, char *p, char *q, int b)
|
||||
{
|
||||
int n, c;
|
||||
|
||||
n = 0;
|
||||
*p = 0;
|
||||
for(;;) {
|
||||
q--;
|
||||
if(q < a)
|
||||
break;
|
||||
c = *q - '0';
|
||||
c = (c<<b) + n;
|
||||
n = c/10;
|
||||
c -= n*10;
|
||||
p--;
|
||||
*p = c + '0';
|
||||
}
|
||||
while(n) {
|
||||
c = n;
|
||||
n = c/10;
|
||||
c -= n*10;
|
||||
p--;
|
||||
*p = c + '0';
|
||||
}
|
||||
}
|
||||
|
||||
static Tab tab2[] =
|
||||
{
|
||||
1, 1, "", // dp = 0-0
|
||||
3, 3, "125",
|
||||
6, 5, "15625",
|
||||
9, 7, "1953125",
|
||||
13, 10, "1220703125",
|
||||
16, 12, "152587890625",
|
||||
19, 14, "19073486328125",
|
||||
23, 17, "11920928955078125",
|
||||
26, 19, "1490116119384765625",
|
||||
27, 19, "7450580596923828125", // dp 8-9
|
||||
};
|
||||
|
||||
static void
|
||||
mulascii(char *a, int *na, int *dp, int *bp)
|
||||
{
|
||||
char *p;
|
||||
int d, b;
|
||||
Tab *t;
|
||||
|
||||
d = -*dp;
|
||||
if(d >= nelem(tab2))
|
||||
d = nelem(tab2)-1;
|
||||
t = tab2 + d;
|
||||
b = t->bp;
|
||||
if(memcmp(a, t->cmp, t->siz) < 0)
|
||||
d--;
|
||||
p = a + *na;
|
||||
*bp -= b;
|
||||
*dp += d;
|
||||
*na += d;
|
||||
mulby(a, p+d, p, b);
|
||||
}
|
||||
|
||||
static int
|
||||
xcmp(char *a, char *b)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
while(c1 = *b++) {
|
||||
c2 = *a++;
|
||||
if(isupper(c2))
|
||||
c2 = tolower(c2);
|
||||
if(c1 != c2)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
4
libc/strtod.h
Normal file
4
libc/strtod.h
Normal file
@ -0,0 +1,4 @@
|
||||
extern double __NaN(void);
|
||||
extern double __Inf(int);
|
||||
extern double __isNaN(double);
|
||||
extern double __isInf(double, int);
|
93
libc/strtoll.c
Normal file
93
libc/strtoll.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#define VLONG_MAX ~(((vlong) 1)<<63)
|
||||
#define VLONG_MIN (((vlong) 1)<<63)
|
||||
vlong
|
||||
strtoll(const char *nptr, char **endptr, int base)
|
||||
{
|
||||
char *p;
|
||||
vlong n, nn, m;
|
||||
int c, ovfl, v, neg, ndig;
|
||||
p = (char*)nptr;
|
||||
neg = 0;
|
||||
n = 0;
|
||||
ndig = 0;
|
||||
ovfl = 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){
|
||||
base = 10;
|
||||
if(*p == '0') {
|
||||
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
|
||||
*/
|
||||
m = VLONG_MAX/base;
|
||||
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;
|
||||
if(n > m)
|
||||
ovfl = 1;
|
||||
nn = n*base + v;
|
||||
if(nn < n)
|
||||
ovfl = 1;
|
||||
n = nn;
|
||||
}
|
||||
Return:
|
||||
if(ndig == 0)
|
||||
p = (char*)nptr;
|
||||
if(endptr)
|
||||
*endptr = p;
|
||||
if(ovfl){
|
||||
if(neg)
|
||||
return VLONG_MIN;
|
||||
return VLONG_MAX;
|
||||
}
|
||||
if(neg)
|
||||
return -n;
|
||||
return n;
|
||||
}
|
30
libc/sysfatal.c
Normal file
30
libc/sysfatal.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <u.h>
|
||||
#include <libc.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);
|
||||
#undef write
|
||||
write(2, buf, strlen(buf));
|
||||
write(2, "\n", 1);
|
||||
panic("sysfatal");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
51
libc/time.c
Normal file
51
libc/time.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
|
||||
/*
|
||||
* After a fork with fd's copied, both fd's are pointing to
|
||||
* the same Chan structure. Since the offset is kept in the Chan
|
||||
* structure, the seek's and read's in the two processes can
|
||||
* compete at moving the offset around. Hence the unusual loop
|
||||
* in the middle of this routine.
|
||||
*/
|
||||
static long
|
||||
oldtime(long *tp)
|
||||
{
|
||||
char b[20];
|
||||
static int f = -1;
|
||||
int i, retries;
|
||||
long t;
|
||||
|
||||
memset(b, 0, sizeof(b));
|
||||
for(retries = 0; retries < 100; retries++){
|
||||
if(f < 0)
|
||||
f = open("/dev/time", OREAD|OCEXEC);
|
||||
if(f < 0)
|
||||
break;
|
||||
if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){
|
||||
close(f);
|
||||
f = -1;
|
||||
} else {
|
||||
if(i != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
t = atol(b);
|
||||
if(tp)
|
||||
*tp = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
long
|
||||
time(long *tp)
|
||||
{
|
||||
vlong t;
|
||||
|
||||
t = nsec()/((vlong)1000000000);
|
||||
if(t == 0)
|
||||
t = oldtime(0);
|
||||
if(tp != nil)
|
||||
*tp = t;
|
||||
return t;
|
||||
}
|
107
libc/tokenize.c
Normal file
107
libc/tokenize.c
Normal file
@ -0,0 +1,107 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static char qsep[] = " \t\r\n";
|
||||
|
||||
static char*
|
||||
qtoken(char *s, char *sep)
|
||||
{
|
||||
int quoting;
|
||||
char *t;
|
||||
|
||||
quoting = 0;
|
||||
t = s; /* s is output string, t is input string */
|
||||
while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
|
||||
if(*t != '\''){
|
||||
*s++ = *t++;
|
||||
continue;
|
||||
}
|
||||
/* *t is a quote */
|
||||
if(!quoting){
|
||||
quoting = 1;
|
||||
t++;
|
||||
continue;
|
||||
}
|
||||
/* quoting and we're on a quote */
|
||||
if(t[1] != '\''){
|
||||
/* end of quoted section; absorb closing quote */
|
||||
t++;
|
||||
quoting = 0;
|
||||
continue;
|
||||
}
|
||||
/* doubled quote; fold one quote into two */
|
||||
t++;
|
||||
*s++ = *t++;
|
||||
}
|
||||
if(*s != '\0'){
|
||||
*s = '\0';
|
||||
if(t == s)
|
||||
t++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static char*
|
||||
etoken(char *t, char *sep)
|
||||
{
|
||||
int quoting;
|
||||
|
||||
/* move to end of next token */
|
||||
quoting = 0;
|
||||
while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
|
||||
if(*t != '\''){
|
||||
t++;
|
||||
continue;
|
||||
}
|
||||
/* *t is a quote */
|
||||
if(!quoting){
|
||||
quoting = 1;
|
||||
t++;
|
||||
continue;
|
||||
}
|
||||
/* quoting and we're on a quote */
|
||||
if(t[1] != '\''){
|
||||
/* end of quoted section; absorb closing quote */
|
||||
t++;
|
||||
quoting = 0;
|
||||
continue;
|
||||
}
|
||||
/* doubled quote; fold one quote into two */
|
||||
t += 2;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
int
|
||||
gettokens(char *s, char **args, int maxargs, char *sep)
|
||||
{
|
||||
int nargs;
|
||||
|
||||
for(nargs=0; nargs<maxargs; nargs++){
|
||||
while(*s!='\0' && utfrune(sep, *s)!=nil)
|
||||
*s++ = '\0';
|
||||
if(*s == '\0')
|
||||
break;
|
||||
args[nargs] = s;
|
||||
s = etoken(s, sep);
|
||||
}
|
||||
|
||||
return nargs;
|
||||
}
|
||||
|
||||
int
|
||||
tokenize(char *s, char **args, int maxargs)
|
||||
{
|
||||
int nargs;
|
||||
|
||||
for(nargs=0; nargs<maxargs; nargs++){
|
||||
while(*s!='\0' && utfrune(qsep, *s)!=nil)
|
||||
s++;
|
||||
if(*s == '\0')
|
||||
break;
|
||||
args[nargs] = s;
|
||||
s = qtoken(s, qsep);
|
||||
}
|
||||
|
||||
return nargs;
|
||||
}
|
17
libc/truerand.c
Normal file
17
libc/truerand.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
ulong
|
||||
truerand(void)
|
||||
{
|
||||
ulong x;
|
||||
static int randfd = -1;
|
||||
|
||||
if(randfd < 0)
|
||||
randfd = open("/dev/random", OREAD|OCEXEC);
|
||||
if(randfd < 0)
|
||||
sysfatal("can't open /dev/random");
|
||||
if(read(randfd, &x, sizeof(x)) != sizeof(x))
|
||||
sysfatal("can't read /dev/random");
|
||||
return x;
|
||||
}
|
53
libc/u16.c
Normal file
53
libc/u16.c
Normal file
@ -0,0 +1,53 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
110
libc/u32.c
Normal file
110
libc/u32.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
127
libc/u64.c
Normal file
127
libc/u64.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
51
libc/utf.h
Normal file
51
libc/utf.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef _UTFH_
|
||||
#define _UTFH_ 1
|
||||
|
||||
typedef unsigned short Rune; /* 16 bits */
|
||||
|
||||
enum
|
||||
{
|
||||
UTFmax = 3, /* maximum bytes per rune */
|
||||
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
|
||||
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
|
||||
Runeerror = 0x80, /* decoding error in UTF */
|
||||
};
|
||||
|
||||
/*
|
||||
* rune routines
|
||||
*/
|
||||
extern int runetochar(char*, Rune*);
|
||||
extern int chartorune(Rune*, char*);
|
||||
extern int runelen(long);
|
||||
extern int runenlen(Rune*, int);
|
||||
extern int fullrune(char*, int);
|
||||
extern int utflen(char*);
|
||||
extern int utfnlen(char*, long);
|
||||
extern char* utfrune(char*, long);
|
||||
extern char* utfrrune(char*, long);
|
||||
extern char* utfutf(char*, char*);
|
||||
extern char* utfecpy(char*, char*, char*);
|
||||
|
||||
extern Rune* runestrcat(Rune*, Rune*);
|
||||
extern Rune* runestrchr(Rune*, Rune);
|
||||
extern int runestrcmp(Rune*, Rune*);
|
||||
extern Rune* runestrcpy(Rune*, Rune*);
|
||||
extern Rune* runestrncpy(Rune*, Rune*, long);
|
||||
extern Rune* runestrecpy(Rune*, Rune*, Rune*);
|
||||
extern Rune* runestrdup(Rune*);
|
||||
extern Rune* runestrncat(Rune*, Rune*, long);
|
||||
extern int runestrncmp(Rune*, Rune*, long);
|
||||
extern Rune* runestrrchr(Rune*, Rune);
|
||||
extern long runestrlen(Rune*);
|
||||
extern Rune* runestrstr(Rune*, Rune*);
|
||||
|
||||
extern Rune tolowerrune(Rune);
|
||||
extern Rune totitlerune(Rune);
|
||||
extern Rune toupperrune(Rune);
|
||||
extern int isalpharune(Rune);
|
||||
extern int islowerrune(Rune);
|
||||
extern int isspacerune(Rune);
|
||||
extern int istitlerune(Rune);
|
||||
extern int isupperrune(Rune);
|
||||
|
||||
#endif
|
14
libc/utfdef.h
Normal file
14
libc/utfdef.h
Normal file
@ -0,0 +1,14 @@
|
||||
#define uchar _utfuchar
|
||||
#define ushort _utfushort
|
||||
#define uint _utfuint
|
||||
#define ulong _utfulong
|
||||
#define vlong _utfvlong
|
||||
#define uvlong _utfuvlong
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#define nil ((void*)0)
|
21
libc/utfecpy.c
Normal file
21
libc/utfecpy.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
23
libc/utflen.c
Normal file
23
libc/utflen.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
26
libc/utfnlen.c
Normal file
26
libc/utfnlen.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
31
libc/utfrrune.c
Normal file
31
libc/utfrrune.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
30
libc/utfrune.c
Normal file
30
libc/utfrune.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
26
libc/utfutf.c
Normal file
26
libc/utfutf.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
|
||||
/*
|
||||
* Return pointer to first occurrence of s2 in s1,
|
||||
* 0 if none
|
||||
*/
|
||||
char*
|
||||
utfutf(char *s1, char *s2)
|
||||
{
|
||||
char *p;
|
||||
long f, n1, n2;
|
||||
Rune r;
|
||||
|
||||
n1 = chartorune(&r, s2);
|
||||
f = r;
|
||||
if(f <= Runesync) /* represents self */
|
||||
return strstr(s1, s2);
|
||||
|
||||
n2 = strlen(s2);
|
||||
for(p=s1; p=utfrune(p, f); p+=n1)
|
||||
if(strncmp(p, s2, n2) == 0)
|
||||
return p;
|
||||
return 0;
|
||||
}
|
34
libc/vfprint.c
Normal file
34
libc/vfprint.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
/*
|
||||
* generic routine for flushing a formatting buffer
|
||||
* to a file descriptor
|
||||
*/
|
||||
int
|
||||
_fmtFdFlush(Fmt *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = (char*)f->to - (char*)f->start;
|
||||
if(n && write((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;
|
||||
}
|
23
libc/vseprint.c
Normal file
23
libc/vseprint.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
||||
|
70
libc/vsmprint.c
Normal file
70
libc/vsmprint.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
static int
|
||||
fmtStrFlush(Fmt *f)
|
||||
{
|
||||
char *s;
|
||||
int n;
|
||||
|
||||
if(f->start == nil)
|
||||
return 0;
|
||||
n = (int)f->farg;
|
||||
n *= 2;
|
||||
s = f->start;
|
||||
f->start = realloc(s, n);
|
||||
if(f->start == nil){
|
||||
f->farg = nil;
|
||||
f->to = nil;
|
||||
f->stop = nil;
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
f->farg = (void*)n;
|
||||
f->to = (char*)f->start + ((char*)f->to - s);
|
||||
f->stop = (char*)f->start + n - 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fmtstrinit(Fmt *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
memset(f, 0, sizeof *f);
|
||||
f->runes = 0;
|
||||
n = 32;
|
||||
f->start = malloc(n);
|
||||
if(f->start == nil)
|
||||
return -1;
|
||||
f->to = f->start;
|
||||
f->stop = (char*)f->start + n - 1;
|
||||
f->flush = fmtStrFlush;
|
||||
f->farg = (void*)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(f.start == nil)
|
||||
return nil;
|
||||
if(n < 0){
|
||||
free(f.start);
|
||||
return nil;
|
||||
}
|
||||
*(char*)f.to = '\0';
|
||||
return f.start;
|
||||
}
|
22
libc/vsnprint.c
Normal file
22
libc/vsnprint.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <u.h>
|
||||
#include <libc.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;
|
||||
}
|
Reference in New Issue
Block a user