This commit is contained in:
Russ Cox
2005-08-08 12:50:13 +00:00
parent 0189e66e88
commit 934846f35c
382 changed files with 62614 additions and 0 deletions

89
libc/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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*)&order;
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
View 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
View 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
View 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
View File

@ -0,0 +1,8 @@
#include <u.h>
#include <libc.h>
int
rand(void)
{
return lrand() & 0x7fff;
}

31
libc/read9pmsg.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

23
libc/runevseprint.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}