Fighting the good fight.
Move libfmt, libutf into subdirectories of lib9. Add poll-based socket i/o to libthread, so that we can avoid using multiple procs when possible, thus removing dependence on crappy pthreads implementations. Convert samterm, acme to the single-proc libthread. Bring libcomplete, acme up-to-date w.r.t. Plan 9 distribution.
This commit is contained in:
parent
d51419bf43
commit
5a8e63b2f0
@ -76,6 +76,7 @@ int isunix;
|
|||||||
Queue *outq;
|
Queue *outq;
|
||||||
Queue *inq;
|
Queue *inq;
|
||||||
int verbose;
|
int verbose;
|
||||||
|
int msize = 8192;
|
||||||
|
|
||||||
void *gethash(Hash**, uint);
|
void *gethash(Hash**, uint);
|
||||||
int puthash(Hash**, uint, void*);
|
int puthash(Hash**, uint, void*);
|
||||||
@ -94,7 +95,6 @@ void *erealloc(void*, int);
|
|||||||
Queue *qalloc(void);
|
Queue *qalloc(void);
|
||||||
int sendq(Queue*, void*);
|
int sendq(Queue*, void*);
|
||||||
void *recvq(Queue*);
|
void *recvq(Queue*);
|
||||||
void pollthread(void*);
|
|
||||||
void connthread(void*);
|
void connthread(void*);
|
||||||
void connoutthread(void*);
|
void connoutthread(void*);
|
||||||
void listenthread(void*);
|
void listenthread(void*);
|
||||||
@ -125,7 +125,6 @@ threadmain(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
char *file;
|
char *file;
|
||||||
|
|
||||||
if(verbose) fprint(2, "9pserve running\n");
|
|
||||||
ARGBEGIN{
|
ARGBEGIN{
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
@ -143,6 +142,7 @@ threadmain(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
}ARGEND
|
}ARGEND
|
||||||
|
|
||||||
|
if(verbose) fprint(2, "9pserve running\n");
|
||||||
if(argc != 1)
|
if(argc != 1)
|
||||||
usage();
|
usage();
|
||||||
addr = argv[0];
|
addr = argv[0];
|
||||||
@ -150,8 +150,19 @@ threadmain(int argc, char **argv)
|
|||||||
if((afd = announce(addr, adir)) < 0)
|
if((afd = announce(addr, adir)) < 0)
|
||||||
sysfatal("announce %s: %r", addr);
|
sysfatal("announce %s: %r", addr);
|
||||||
|
|
||||||
proccreate(mainproc, nil, STACK);
|
if(verbose) fprint(2, "9pserve forking\n");
|
||||||
threadexits(0);
|
switch(fork()){
|
||||||
|
case -1:
|
||||||
|
sysfatal("fork: %r");
|
||||||
|
case 0:
|
||||||
|
if(verbose) fprint(2, "running mainproc\n");
|
||||||
|
mainproc(nil);
|
||||||
|
if(verbose) fprint(2, "mainproc finished\n");
|
||||||
|
_exits(0);
|
||||||
|
default:
|
||||||
|
if(verbose) fprint(2, "9pserve exiting\n");
|
||||||
|
_exits(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -161,8 +172,6 @@ mainproc(void *v)
|
|||||||
Fcall f;
|
Fcall f;
|
||||||
USED(v);
|
USED(v);
|
||||||
|
|
||||||
yield(); /* let threadmain exit */
|
|
||||||
|
|
||||||
atnotify(ignorepipe, 1);
|
atnotify(ignorepipe, 1);
|
||||||
fmtinstall('D', dirfmt);
|
fmtinstall('D', dirfmt);
|
||||||
fmtinstall('M', dirmodefmt);
|
fmtinstall('M', dirmodefmt);
|
||||||
@ -174,7 +183,7 @@ mainproc(void *v)
|
|||||||
|
|
||||||
f.type = Tversion;
|
f.type = Tversion;
|
||||||
f.version = "9P2000";
|
f.version = "9P2000";
|
||||||
f.msize = 8192;
|
f.msize = msize;
|
||||||
f.tag = NOTAG;
|
f.tag = NOTAG;
|
||||||
n = convS2M(&f, vbuf, sizeof vbuf);
|
n = convS2M(&f, vbuf, sizeof vbuf);
|
||||||
if(verbose > 1) fprint(2, "* <- %F\n", &f);
|
if(verbose > 1) fprint(2, "* <- %F\n", &f);
|
||||||
@ -182,12 +191,13 @@ mainproc(void *v)
|
|||||||
n = read9pmsg(0, vbuf, sizeof vbuf);
|
n = read9pmsg(0, vbuf, sizeof vbuf);
|
||||||
if(convM2S(vbuf, n, &f) != n)
|
if(convM2S(vbuf, n, &f) != n)
|
||||||
sysfatal("convM2S failure");
|
sysfatal("convM2S failure");
|
||||||
|
if(f.msize < msize)
|
||||||
|
msize = f.msize;
|
||||||
if(verbose > 1) fprint(2, "* -> %F\n", &f);
|
if(verbose > 1) fprint(2, "* -> %F\n", &f);
|
||||||
|
|
||||||
threadcreate(inputthread, nil, STACK);
|
threadcreate(inputthread, nil, STACK);
|
||||||
threadcreate(outputthread, nil, STACK);
|
threadcreate(outputthread, nil, STACK);
|
||||||
threadcreate(listenthread, nil, STACK);
|
threadcreate(listenthread, nil, STACK);
|
||||||
threadcreateidle(pollthread, nil, STACK);
|
|
||||||
threadexits(0);
|
threadexits(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,8 +306,8 @@ connthread(void *arg)
|
|||||||
case Tversion:
|
case Tversion:
|
||||||
m->rx.tag = m->tx.tag;
|
m->rx.tag = m->tx.tag;
|
||||||
m->rx.msize = m->tx.msize;
|
m->rx.msize = m->tx.msize;
|
||||||
if(m->rx.msize > 8192)
|
if(m->rx.msize > msize)
|
||||||
m->rx.msize = 8192;
|
m->rx.msize = msize;
|
||||||
m->rx.version = "9P2000";
|
m->rx.version = "9P2000";
|
||||||
m->rx.type = Rversion;
|
m->rx.type = Rversion;
|
||||||
send9pmsg(m);
|
send9pmsg(m);
|
||||||
@ -480,7 +490,7 @@ openfdthread(void *v)
|
|||||||
m->internal = 1;
|
m->internal = 1;
|
||||||
m->c = c;
|
m->c = c;
|
||||||
m->tx.type = Tread;
|
m->tx.type = Tread;
|
||||||
m->tx.count = 8192;
|
m->tx.count = msize - IOHDRSZ;
|
||||||
m->tx.fid = fid->fid;
|
m->tx.fid = fid->fid;
|
||||||
m->tx.tag = m->tag;
|
m->tx.tag = m->tag;
|
||||||
m->tx.offset = tot;
|
m->tx.offset = tot;
|
||||||
@ -506,7 +516,10 @@ openfdthread(void *v)
|
|||||||
}else{
|
}else{
|
||||||
for(;;){
|
for(;;){
|
||||||
if(verbose) fprint(2, "twrite...");
|
if(verbose) fprint(2, "twrite...");
|
||||||
if((n=ioread(io, c->fd, buf, sizeof buf)) <= 0){
|
n = sizeof buf;
|
||||||
|
if(n > msize)
|
||||||
|
n = msize;
|
||||||
|
if((n=ioread(io, c->fd, buf, n)) <= 0){
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
fprint(2, "pipe read error: %r\n");
|
fprint(2, "pipe read error: %r\n");
|
||||||
m = nil;
|
m = nil;
|
||||||
@ -1122,106 +1135,23 @@ struct Ioproc
|
|||||||
int index;
|
int index;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct Ioproc **pio;
|
|
||||||
static struct pollfd *pfd;
|
|
||||||
static int npfd;
|
|
||||||
static struct Ioproc *iofree;
|
|
||||||
|
|
||||||
Ioproc*
|
Ioproc*
|
||||||
ioproc(void)
|
ioproc(void)
|
||||||
{
|
{
|
||||||
Ioproc *io;
|
return (Ioproc*)-1;
|
||||||
|
|
||||||
if(iofree == nil){
|
|
||||||
pfd = erealloc(pfd, (npfd+1)*sizeof(pfd[0]));
|
|
||||||
pfd[npfd].events = 0;
|
|
||||||
pfd[npfd].fd = -1;
|
|
||||||
iofree = emalloc(sizeof(Ioproc));
|
|
||||||
iofree->index = npfd;
|
|
||||||
iofree->c = chancreate(sizeof(ulong), 1);
|
|
||||||
pio = erealloc(pio, (npfd+1)*sizeof(pio[0]));
|
|
||||||
pio[npfd] = iofree;
|
|
||||||
npfd++;
|
|
||||||
}
|
|
||||||
io = iofree;
|
|
||||||
iofree = io->next;
|
|
||||||
return io;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
closeioproc(Ioproc *io)
|
closeioproc(Ioproc *io)
|
||||||
{
|
{
|
||||||
io->next = iofree;
|
|
||||||
iofree = io;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pollthread(void *v)
|
|
||||||
{
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
yield();
|
|
||||||
for(i=0; i<npfd; i++)
|
|
||||||
pfd[i].revents = 0;
|
|
||||||
if(verbose){
|
|
||||||
fprint(2, "poll:");
|
|
||||||
for(i=0; i<npfd; i++)
|
|
||||||
if(pfd[i].events)
|
|
||||||
fprint(2, " %d%c", pfd[i].fd, pfd[i].events==POLLIN ? 'r' : pfd[i].events==POLLOUT ? 'w' : '?');
|
|
||||||
fprint(2, "\n");
|
|
||||||
}
|
|
||||||
n = poll(pfd, npfd, -1);
|
|
||||||
if(n <= 0)
|
|
||||||
continue;
|
|
||||||
for(i=0; i<npfd; i++)
|
|
||||||
if(pfd[i].fd != -1 && pfd[i].revents){
|
|
||||||
pfd[i].fd = -1;
|
|
||||||
pfd[i].events = 0;
|
|
||||||
pfd[i].revents = 0;
|
|
||||||
nbsendul(pio[i]->c, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
noblock(int fd)
|
|
||||||
{
|
|
||||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)|O_NONBLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
xwait(Ioproc *io, int fd, int e)
|
|
||||||
{
|
|
||||||
if(verbose) fprint(2, "wait for %d%c\n", fd, e==POLLIN ? 'r' : 'w');
|
|
||||||
pfd[io->index].fd = fd;
|
|
||||||
pfd[io->index].events = e;
|
|
||||||
recvul(io->c);
|
|
||||||
if(verbose) fprint(2, "got %d\n", fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rwait(Ioproc *io, int fd)
|
|
||||||
{
|
|
||||||
xwait(io, fd, POLLIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wwait(Ioproc *io, int fd)
|
|
||||||
{
|
|
||||||
xwait(io, fd, POLLOUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long
|
long
|
||||||
ioread(Ioproc *io, int fd, void *v, long n)
|
ioread(Ioproc *io, int fd, void *v, long n)
|
||||||
{
|
{
|
||||||
long r;
|
|
||||||
USED(io);
|
USED(io);
|
||||||
|
|
||||||
noblock(fd);
|
return threadread(fd, v, n);
|
||||||
while((r=read(fd, v, n)) < 0 && errno == EWOULDBLOCK)
|
|
||||||
rwait(io, fd);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long
|
long
|
||||||
@ -1247,9 +1177,16 @@ iorecvfd(Ioproc *io, int fd)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
noblock(fd);
|
threadfdnoblock(fd);
|
||||||
while((r=recvfd(fd)) < 0 && errno == EWOULDBLOCK)
|
while((r=recvfd(fd)) < 0){
|
||||||
rwait(io, fd);
|
if(errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if(errno == EWOULDBLOCK || errno == EAGAIN){
|
||||||
|
threadfdwait(fd, 'r');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1258,23 +1195,24 @@ iosendfd(Ioproc *io, int s, int fd)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
noblock(s);
|
threadfdnoblock(s);
|
||||||
while((r=sendfd(s, fd)) < 0 && errno == EWOULDBLOCK)
|
while((r=sendfd(s, fd)) < 0){
|
||||||
wwait(io, s);
|
if(errno == EINTR)
|
||||||
if(r < 0) fprint(2, "sent %d, %d\n", s, fd);
|
continue;
|
||||||
|
if(errno == EWOULDBLOCK || errno == EAGAIN){
|
||||||
|
threadfdwait(fd, 'w');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
_iowrite(Ioproc *io, int fd, void *v, long n)
|
_iowrite(Ioproc *io, int fd, void *v, long n)
|
||||||
{
|
{
|
||||||
long r;
|
|
||||||
USED(io);
|
USED(io);
|
||||||
|
return threadwrite(fd, v, n);
|
||||||
noblock(fd);
|
|
||||||
while((r=write(fd, v, n)) < 0 && errno == EWOULDBLOCK)
|
|
||||||
wwait(io, fd);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long
|
long
|
||||||
@ -1305,9 +1243,16 @@ iolisten(Ioproc *io, char *dir, char *ndir)
|
|||||||
|
|
||||||
if((fd = _p9netfd(dir)) < 0)
|
if((fd = _p9netfd(dir)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
noblock(fd);
|
threadfdnoblock(fd);
|
||||||
while((r=listen(dir, ndir)) < 0 && errno == EWOULDBLOCK)
|
while((r=listen(dir, ndir)) < 0){
|
||||||
rwait(io, fd);
|
if(errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if(errno == EWOULDBLOCK || errno == EAGAIN){
|
||||||
|
threadfdwait(fd, 'r');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1317,9 +1262,16 @@ ioaccept(Ioproc *io, int fd, char *dir)
|
|||||||
int r;
|
int r;
|
||||||
USED(io);
|
USED(io);
|
||||||
|
|
||||||
noblock(fd);
|
threadfdnoblock(fd);
|
||||||
while((r=accept(fd, dir)) < 0 && errno == EWOULDBLOCK)
|
while((r=accept(fd, dir)) < 0){
|
||||||
rwait(io, fd);
|
if(errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if(errno == EWOULDBLOCK || errno == EAGAIN){
|
||||||
|
threadfdwait(fd, 'r');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,6 @@ threadmain(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *p, *loadfile;
|
char *p, *loadfile;
|
||||||
char buf[256];
|
|
||||||
Column *c;
|
Column *c;
|
||||||
int ncol;
|
int ncol;
|
||||||
Display *d;
|
Display *d;
|
||||||
@ -70,6 +69,9 @@ threadmain(int argc, char *argv[])
|
|||||||
|
|
||||||
loadfile = nil;
|
loadfile = nil;
|
||||||
ARGBEGIN{
|
ARGBEGIN{
|
||||||
|
case 'a':
|
||||||
|
globalautoindent = TRUE;
|
||||||
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
bartflag = TRUE;
|
bartflag = TRUE;
|
||||||
break;
|
break;
|
||||||
@ -98,7 +100,7 @@ threadmain(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Usage:
|
Usage:
|
||||||
fprint(2, "usage: acme -c ncol -f fontname -F fixedwidthfontname -l loadfile\n");
|
fprint(2, "usage: acme -a -c ncol -f fontname -F fixedwidthfontname -l loadfile\n");
|
||||||
exits("usage");
|
exits("usage");
|
||||||
}ARGEND
|
}ARGEND
|
||||||
|
|
||||||
@ -183,7 +185,7 @@ threadmain(int argc, char *argv[])
|
|||||||
fprint(2, "acme: can't initialize plumber: %r\n");
|
fprint(2, "acme: can't initialize plumber: %r\n");
|
||||||
else{
|
else{
|
||||||
cplumb = chancreate(sizeof(Plumbmsg*), 0);
|
cplumb = chancreate(sizeof(Plumbmsg*), 0);
|
||||||
proccreate(plumbproc, nil, STACK);
|
threadcreate(plumbproc, nil, STACK);
|
||||||
}
|
}
|
||||||
plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
|
plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
|
||||||
|
|
||||||
@ -315,7 +317,7 @@ acmeerrorproc(void *v)
|
|||||||
USED(v);
|
USED(v);
|
||||||
threadsetname("acmeerrorproc");
|
threadsetname("acmeerrorproc");
|
||||||
buf = emalloc(8192+1);
|
buf = emalloc(8192+1);
|
||||||
while((n=read(errorfd, buf, 8192)) >= 0){
|
while((n=threadread(errorfd, buf, 8192)) >= 0){
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
sendp(cerr, estrdup(buf));
|
sendp(cerr, estrdup(buf));
|
||||||
}
|
}
|
||||||
@ -324,8 +326,7 @@ acmeerrorproc(void *v)
|
|||||||
void
|
void
|
||||||
acmeerrorinit(void)
|
acmeerrorinit(void)
|
||||||
{
|
{
|
||||||
int fd, pfd[2];
|
int pfd[2];
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
if(pipe(pfd) < 0)
|
if(pipe(pfd) < 0)
|
||||||
error("can't create pipe");
|
error("can't create pipe");
|
||||||
@ -351,7 +352,7 @@ acmeerrorinit(void)
|
|||||||
errorfd = pfd[1];
|
errorfd = pfd[1];
|
||||||
if(errorfd < 0)
|
if(errorfd < 0)
|
||||||
error("can't re-open acmeerror file");
|
error("can't re-open acmeerror file");
|
||||||
proccreate(acmeerrorproc, nil, STACK);
|
threadcreate(acmeerrorproc, nil, STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -362,7 +363,7 @@ plumbproc(void *v)
|
|||||||
USED(v);
|
USED(v);
|
||||||
threadsetname("plumbproc");
|
threadsetname("plumbproc");
|
||||||
for(;;){
|
for(;;){
|
||||||
m = plumbrecv(plumbeditfd);
|
m = threadplumbrecv(plumbeditfd);
|
||||||
if(m == nil)
|
if(m == nil)
|
||||||
threadexits(nil);
|
threadexits(nil);
|
||||||
sendp(cplumb, m);
|
sendp(cplumb, m);
|
||||||
@ -399,6 +400,7 @@ keyboardthread(void *v)
|
|||||||
winlock(t->w, 'K');
|
winlock(t->w, 'K');
|
||||||
wincommit(t->w, t);
|
wincommit(t->w, t);
|
||||||
winunlock(t->w);
|
winunlock(t->w);
|
||||||
|
flushwarnings(1);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
}
|
}
|
||||||
alts[KTimer].c = nil;
|
alts[KTimer].c = nil;
|
||||||
@ -425,6 +427,7 @@ keyboardthread(void *v)
|
|||||||
}
|
}
|
||||||
if(nbrecv(keyboardctl->c, &r) > 0)
|
if(nbrecv(keyboardctl->c, &r) > 0)
|
||||||
goto casekeyboard;
|
goto casekeyboard;
|
||||||
|
flushwarnings(1);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -467,6 +470,7 @@ mousethread(void *v)
|
|||||||
draw(screen, screen->r, display->white, nil, ZP);
|
draw(screen, screen->r, display->white, nil, ZP);
|
||||||
scrlresize();
|
scrlresize();
|
||||||
rowresize(&row, screen->clipr);
|
rowresize(&row, screen->clipr);
|
||||||
|
flushwarnings(1);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
break;
|
break;
|
||||||
case MPlumb:
|
case MPlumb:
|
||||||
@ -477,6 +481,7 @@ mousethread(void *v)
|
|||||||
else if(strcmp(act, "showdata")==0)
|
else if(strcmp(act, "showdata")==0)
|
||||||
plumbshow(pm);
|
plumbshow(pm);
|
||||||
}
|
}
|
||||||
|
flushwarnings(1);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
plumbfree(pm);
|
plumbfree(pm);
|
||||||
break;
|
break;
|
||||||
@ -562,6 +567,7 @@ mousethread(void *v)
|
|||||||
goto Continue;
|
goto Continue;
|
||||||
}
|
}
|
||||||
Continue:
|
Continue:
|
||||||
|
flushwarnings(0);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
qunlock(&row.lk);
|
qunlock(&row.lk);
|
||||||
break;
|
break;
|
||||||
@ -916,36 +922,48 @@ iconinit(void)
|
|||||||
void
|
void
|
||||||
acmeputsnarf(void)
|
acmeputsnarf(void)
|
||||||
{
|
{
|
||||||
int fd, i, n;
|
int i, n;
|
||||||
|
Fmt f;
|
||||||
|
char *s;
|
||||||
|
|
||||||
if(snarffd<0 || snarfbuf.nc==0)
|
if(snarfbuf.nc==0)
|
||||||
return;
|
return;
|
||||||
if(snarfbuf.nc > MAXSNARF)
|
if(snarfbuf.nc > MAXSNARF)
|
||||||
return;
|
return;
|
||||||
fd = open("/dev/snarf", OWRITE);
|
|
||||||
if(fd < 0)
|
fmtstrinit(&f);
|
||||||
return;
|
|
||||||
for(i=0; i<snarfbuf.nc; i+=n){
|
for(i=0; i<snarfbuf.nc; i+=n){
|
||||||
n = snarfbuf.nc-i;
|
n = snarfbuf.nc-i;
|
||||||
if(n >= NSnarf)
|
if(n >= NSnarf)
|
||||||
n = NSnarf;
|
n = NSnarf;
|
||||||
bufread(&snarfbuf, i, snarfrune, n);
|
bufread(&snarfbuf, i, snarfrune, n);
|
||||||
if(fprint(fd, "%.*S", n, snarfrune) < 0)
|
if(fmtprint(&f, "%.*S", n, snarfrune) < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
close(fd);
|
s = fmtstrflush(&f);
|
||||||
|
if(s && s[0])
|
||||||
|
putsnarf(s);
|
||||||
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
acmegetsnarf()
|
acmegetsnarf(void)
|
||||||
{
|
{
|
||||||
int nulls;
|
char *s;
|
||||||
|
int nb, nr, nulls, len;
|
||||||
|
Rune *r;
|
||||||
|
|
||||||
if(snarfbuf.nc > MAXSNARF)
|
s = getsnarf();
|
||||||
|
if(s == nil || s[0]==0){
|
||||||
|
free(s);
|
||||||
return;
|
return;
|
||||||
if(snarffd < 0)
|
}
|
||||||
return;
|
|
||||||
seek(snarffd, 0, 0);
|
len = strlen(s);
|
||||||
|
r = runemalloc(len+1);
|
||||||
|
cvttorunes(s, len, r, &nb, &nr, &nulls);
|
||||||
bufreset(&snarfbuf);
|
bufreset(&snarfbuf);
|
||||||
bufload(&snarfbuf, 0, snarffd, &nulls);
|
bufinsert(&snarfbuf, 0, r, nr);
|
||||||
|
free(r);
|
||||||
|
free(s);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -232,6 +232,7 @@ struct Window
|
|||||||
uchar isscratch;
|
uchar isscratch;
|
||||||
uchar filemenu;
|
uchar filemenu;
|
||||||
uchar dirty;
|
uchar dirty;
|
||||||
|
uchar autoindent;
|
||||||
int id;
|
int id;
|
||||||
Range addr;
|
Range addr;
|
||||||
Range limit;
|
Range limit;
|
||||||
@ -486,6 +487,7 @@ enum /* editing */
|
|||||||
Collecting,
|
Collecting,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint globalincref;
|
||||||
uint seq;
|
uint seq;
|
||||||
uint maxtab; /* size of a tab, in units of the '0' character */
|
uint maxtab; /* size of a tab, in units of the '0' character */
|
||||||
|
|
||||||
@ -524,10 +526,11 @@ Image *tagcols[NCOL];
|
|||||||
Image *textcols[NCOL];
|
Image *textcols[NCOL];
|
||||||
int plumbsendfd;
|
int plumbsendfd;
|
||||||
int plumbeditfd;
|
int plumbeditfd;
|
||||||
extern char wdir[];
|
extern char wdir[]; /* must use extern because no dimension given */
|
||||||
int editing;
|
int editing;
|
||||||
int erroutfd;
|
int erroutfd;
|
||||||
int messagesize; /* negotiated in 9P version setup */
|
int messagesize; /* negotiated in 9P version setup */
|
||||||
|
int globalautoindent;
|
||||||
|
|
||||||
Channel *ckeyboard; /* chan(Rune)[10] */
|
Channel *ckeyboard; /* chan(Rune)[10] */
|
||||||
Channel *cplumb; /* chan(Plumbmsg*) */
|
Channel *cplumb; /* chan(Plumbmsg*) */
|
||||||
|
|||||||
@ -596,7 +596,7 @@ runpipe(Text *t, int cmd, Rune *cr, int ncr, int state)
|
|||||||
|
|
||||||
r = skipbl(cr, ncr, &n);
|
r = skipbl(cr, ncr, &n);
|
||||||
if(n == 0)
|
if(n == 0)
|
||||||
editerror("no command specified for >");
|
editerror("no command specified for %c", cmd);
|
||||||
w = nil;
|
w = nil;
|
||||||
if(state == Inserting){
|
if(state == Inserting){
|
||||||
w = t->w;
|
w = t->w;
|
||||||
@ -949,12 +949,15 @@ filelooper(Cmd *cp, int XY)
|
|||||||
/*
|
/*
|
||||||
* add a ref to all windows to keep safe windows accessed by X
|
* add a ref to all windows to keep safe windows accessed by X
|
||||||
* that would not otherwise have a ref to hold them up during
|
* that would not otherwise have a ref to hold them up during
|
||||||
* the shenanigans.
|
* the shenanigans. note this with globalincref so that any
|
||||||
|
* newly created windows start with an extra reference.
|
||||||
*/
|
*/
|
||||||
allwindows(alllocker, (void*)1);
|
allwindows(alllocker, (void*)1);
|
||||||
|
globalincref = 1;
|
||||||
for(i=0; i<loopstruct.nw; i++)
|
for(i=0; i<loopstruct.nw; i++)
|
||||||
cmdexec(&loopstruct.w[i]->body, cp->u.cmd);
|
cmdexec(&loopstruct.w[i]->body, cp->u.cmd);
|
||||||
allwindows(alllocker, (void*)0);
|
allwindows(alllocker, (void*)0);
|
||||||
|
globalincref = 0;
|
||||||
free(loopstruct.w);
|
free(loopstruct.w);
|
||||||
loopstruct.w = nil;
|
loopstruct.w = nil;
|
||||||
|
|
||||||
|
|||||||
@ -462,7 +462,7 @@ getname(Text *t, Text *argt, Rune *arg, int narg, int isput)
|
|||||||
dir.nr = 0;
|
dir.nr = 0;
|
||||||
if(n>0 && arg[0]!='/'){
|
if(n>0 && arg[0]!='/'){
|
||||||
dir = dirname(t, nil, 0);
|
dir = dirname(t, nil, 0);
|
||||||
if(n==1 && dir.r[0]=='.'){ /* sigh */
|
if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */
|
||||||
free(dir.r);
|
free(dir.r);
|
||||||
dir.r = nil;
|
dir.r = nil;
|
||||||
dir.nr = 0;
|
dir.nr = 0;
|
||||||
@ -606,15 +606,15 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname)
|
|||||||
f->qidpath = d->qid.path;
|
f->qidpath = d->qid.path;
|
||||||
f->mtime = d->mtime;
|
f->mtime = d->mtime;
|
||||||
if(f->unread)
|
if(f->unread)
|
||||||
warningew(w, nil, "%s not written; file already exists\n", name);
|
warning(nil, "%s not written; file already exists\n", name);
|
||||||
else
|
else
|
||||||
warningew(w, nil, "%s modified%s%s since last read\n", name, d->muid[0]?" by ":"", d->muid);
|
warning(nil, "%s modified%s%s since last read\n", name, d->muid[0]?" by ":"", d->muid);
|
||||||
goto Rescue1;
|
goto Rescue1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fd = create(name, OWRITE, 0666);
|
fd = create(name, OWRITE, 0666);
|
||||||
if(fd < 0){
|
if(fd < 0){
|
||||||
warningew(w, nil, "can't create file %s: %r\n", name);
|
warning(nil, "can't create file %s: %r\n", name);
|
||||||
goto Rescue1;
|
goto Rescue1;
|
||||||
}
|
}
|
||||||
r = fbufalloc();
|
r = fbufalloc();
|
||||||
@ -623,7 +623,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname)
|
|||||||
d = dirfstat(fd);
|
d = dirfstat(fd);
|
||||||
isapp = (d!=nil && d->length>0 && (d->qid.type&QTAPPEND));
|
isapp = (d!=nil && d->length>0 && (d->qid.type&QTAPPEND));
|
||||||
if(isapp){
|
if(isapp){
|
||||||
warningew(w, nil, "%s not written; file is append only\n", name);
|
warning(nil, "%s not written; file is append only\n", name);
|
||||||
goto Rescue2;
|
goto Rescue2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,7 +634,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname)
|
|||||||
bufread(&f->b, q, r, n);
|
bufread(&f->b, q, r, n);
|
||||||
m = snprint(s, BUFSIZE+1, "%.*S", n, r);
|
m = snprint(s, BUFSIZE+1, "%.*S", n, r);
|
||||||
if(write(fd, s, m) != m){
|
if(write(fd, s, m) != m){
|
||||||
warningew(w, nil, "can't write file %s: %r\n", name);
|
warning(nil, "can't write file %s: %r\n", name);
|
||||||
goto Rescue2;
|
goto Rescue2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -701,7 +701,7 @@ put(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
|
|||||||
f = w->body.file;
|
f = w->body.file;
|
||||||
name = getname(&w->body, argt, arg, narg, TRUE);
|
name = getname(&w->body, argt, arg, narg, TRUE);
|
||||||
if(name == nil){
|
if(name == nil){
|
||||||
warningew(w, nil, "no file name\n");
|
warning(nil, "no file name\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
namer = bytetorune(name, &nname);
|
namer = bytetorune(name, &nname);
|
||||||
@ -1163,6 +1163,58 @@ incl(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Rune LON[] = { 'O', 'N', 0 };
|
||||||
|
static Rune LOFF[] = { 'O', 'F', 'F', 0 };
|
||||||
|
static Rune Lon[] = { 'o', 'n', 0 };
|
||||||
|
|
||||||
|
static int
|
||||||
|
indentval(Rune *s, int n)
|
||||||
|
{
|
||||||
|
if(n < 2)
|
||||||
|
return -1;
|
||||||
|
if(runestrncmp(s, LON, n) == 0){
|
||||||
|
globalautoindent = TRUE;
|
||||||
|
warning(nil, "Indent ON\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if(runestrncmp(s, LOFF, n) == 0){
|
||||||
|
globalautoindent = FALSE;
|
||||||
|
warning(nil, "Indent OFF\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
return runestrncmp(s, Lon, n) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
indent(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
|
||||||
|
{
|
||||||
|
Rune *a, *r;
|
||||||
|
Window *w;
|
||||||
|
int na, len, autoindent;
|
||||||
|
|
||||||
|
USED(_0);
|
||||||
|
USED(_1);
|
||||||
|
USED(_2);
|
||||||
|
|
||||||
|
if(et==nil || et->w==nil)
|
||||||
|
return;
|
||||||
|
w = et->w;
|
||||||
|
autoindent = -1;
|
||||||
|
getarg(argt, FALSE, TRUE, &r, &len);
|
||||||
|
if(r!=nil && len>0)
|
||||||
|
autoindent = indentval(r, len);
|
||||||
|
else{
|
||||||
|
a = findbl(arg, narg, &na);
|
||||||
|
if(a != arg)
|
||||||
|
autoindent = indentval(arg, narg-na);
|
||||||
|
}
|
||||||
|
if(autoindent >= 0)
|
||||||
|
w->autoindent = autoindent;
|
||||||
|
if(autoindent != 2)
|
||||||
|
warning(nil, "%.*S: Indent %s\n", w->body.file->nname, w->body.file->name,
|
||||||
|
w->autoindent ? "on" : "off");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tab(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
|
tab(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
|
||||||
{
|
{
|
||||||
@ -1375,7 +1427,7 @@ runproc(void *argvp)
|
|||||||
av[ac++] = arg;
|
av[ac++] = arg;
|
||||||
av[ac] = nil;
|
av[ac] = nil;
|
||||||
c->av = av;
|
c->av = av;
|
||||||
procexec(cpid, sfd, av[0], av);
|
threadexec(cpid, sfd, av[0], av);
|
||||||
/* libthread uses execvp so no need to do this */
|
/* libthread uses execvp so no need to do this */
|
||||||
#if 0
|
#if 0
|
||||||
e = av[0];
|
e = av[0];
|
||||||
@ -1419,10 +1471,10 @@ Hard:
|
|||||||
c->text = news;
|
c->text = news;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
procexecl(cpid, sfd, "rc", "rc", "-c", t, nil);
|
threadexecl(cpid, sfd, "rc", "rc", "-c", t, nil);
|
||||||
|
|
||||||
Fail:
|
Fail:
|
||||||
/* procexec hasn't happened, so send a zero */
|
/* threadexec hasn't happened, so send a zero */
|
||||||
close(sfd[0]);
|
close(sfd[0]);
|
||||||
close(sfd[1]);
|
close(sfd[1]);
|
||||||
if(sfd[2] != sfd[1])
|
if(sfd[2] != sfd[1])
|
||||||
@ -1482,7 +1534,7 @@ run(Window *win, char *s, Rune *rdir, int ndir, int newns, char *argaddr, char *
|
|||||||
arg[7] = c;
|
arg[7] = c;
|
||||||
arg[8] = cpid;
|
arg[8] = cpid;
|
||||||
arg[9] = (void*)iseditcmd;
|
arg[9] = (void*)iseditcmd;
|
||||||
proccreate(runproc, arg, STACK);
|
threadcreate(runproc, arg, STACK);
|
||||||
/* mustn't block here because must be ready to answer mount() call in run() */
|
/* mustn't block here because must be ready to answer mount() call in run() */
|
||||||
arg = emalloc(2*sizeof(void*));
|
arg = emalloc(2*sizeof(void*));
|
||||||
arg[0] = c;
|
arg[0] = c;
|
||||||
|
|||||||
@ -27,7 +27,7 @@ void clearmouse(void);
|
|||||||
void allwindows(void(*)(Window*, void*), void*);
|
void allwindows(void(*)(Window*, void*), void*);
|
||||||
uint loadfile(int, uint, int*, int(*)(void*, uint, Rune*, int), void*);
|
uint loadfile(int, uint, int*, int(*)(void*, uint, Rune*, int), void*);
|
||||||
|
|
||||||
Window* errorwin(Mntdir*, int, Window*);
|
Window* errorwin(Mntdir*, int);
|
||||||
Runestr cleanrname(Runestr);
|
Runestr cleanrname(Runestr);
|
||||||
void run(Window*, char*, Rune*, int, int, char*, char*, int);
|
void run(Window*, char*, Rune*, int, int, char*, char*, int);
|
||||||
void fsysclose(void);
|
void fsysclose(void);
|
||||||
@ -86,6 +86,7 @@ int expand(Text*, uint, uint, Expand*);
|
|||||||
Rune* skipbl(Rune*, int, int*);
|
Rune* skipbl(Rune*, int, int*);
|
||||||
Rune* findbl(Rune*, int, int*);
|
Rune* findbl(Rune*, int, int*);
|
||||||
char* edittext(Window*, int, Rune*, int);
|
char* edittext(Window*, int, Rune*, int);
|
||||||
|
void flushwarnings(int);
|
||||||
|
|
||||||
#define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune))
|
#define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune))
|
||||||
#define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune))
|
#define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune))
|
||||||
|
|||||||
@ -111,8 +111,7 @@ void
|
|||||||
fsysinit(void)
|
fsysinit(void)
|
||||||
{
|
{
|
||||||
int p[2];
|
int p[2];
|
||||||
int n, fd;
|
char *u;
|
||||||
char buf[256], *u;
|
|
||||||
|
|
||||||
if(pipe(p) < 0)
|
if(pipe(p) < 0)
|
||||||
error("can't create pipe");
|
error("can't create pipe");
|
||||||
@ -122,7 +121,7 @@ fsysinit(void)
|
|||||||
fmtinstall('F', fcallfmt);
|
fmtinstall('F', fcallfmt);
|
||||||
if((u = getuser()) != nil)
|
if((u = getuser()) != nil)
|
||||||
user = estrdup(u);
|
user = estrdup(u);
|
||||||
proccreate(fsysproc, nil, STACK);
|
threadcreate(fsysproc, nil, STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -138,7 +137,7 @@ fsysproc(void *v)
|
|||||||
x = nil;
|
x = nil;
|
||||||
for(;;){
|
for(;;){
|
||||||
buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
|
buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
|
||||||
n = read9pmsg(sfd, buf, messagesize);
|
n = threadread9pmsg(sfd, buf, messagesize);
|
||||||
if(n <= 0){
|
if(n <= 0){
|
||||||
if(closing)
|
if(closing)
|
||||||
break;
|
break;
|
||||||
@ -255,7 +254,11 @@ respond(Xfid *x, Fcall *t, char *err)
|
|||||||
x->buf = emalloc(messagesize);
|
x->buf = emalloc(messagesize);
|
||||||
n = convS2M(t, x->buf, messagesize);
|
n = convS2M(t, x->buf, messagesize);
|
||||||
if(n <= 0)
|
if(n <= 0)
|
||||||
|
{
|
||||||
|
fprint(2, "convert error (n=%d, msgsize %d): have %F\n", n, messagesize, &x->fcall);
|
||||||
|
fprint(2, "\tresponse: %F\n", t);
|
||||||
error("convert error in convS2M");
|
error("convert error in convS2M");
|
||||||
|
}
|
||||||
if(write(sfd, x->buf, n) != n)
|
if(write(sfd, x->buf, n) != n)
|
||||||
error("write error in respond");
|
error("write error in respond");
|
||||||
free(x->buf);
|
free(x->buf);
|
||||||
|
|||||||
@ -320,60 +320,18 @@ isfilec(Rune r)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Runestr wrapper for cleanname */
|
||||||
Runestr
|
Runestr
|
||||||
cleanrname(Runestr rs)
|
cleanrname(Runestr rs)
|
||||||
{
|
{
|
||||||
int i, j, found;
|
char *s;
|
||||||
Rune *b;
|
int nb, nulls;
|
||||||
int n;
|
|
||||||
static Rune Lslashdotdot[] = { '/', '.', '.', 0 };
|
|
||||||
|
|
||||||
b = rs.r;
|
s = runetobyte(rs.r, rs.nr);
|
||||||
n = rs.nr;
|
cleanname(s);
|
||||||
|
cvttorunes(s, strlen(s), rs.r, &nb, &rs.nr, &nulls);
|
||||||
/* compress multiple slashes */
|
free(s);
|
||||||
for(i=0; i<n-1; i++)
|
return rs;
|
||||||
if(b[i]=='/' && b[i+1]=='/'){
|
|
||||||
runemove(b+i, b+i+1, n-i-1);
|
|
||||||
--n;
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
/* eliminate ./ */
|
|
||||||
for(i=0; i<n-1; i++)
|
|
||||||
if(b[i]=='.' && b[i+1]=='/' && (i==0 || b[i-1]=='/')){
|
|
||||||
runemove(b+i, b+i+2, n-i-2);
|
|
||||||
n -= 2;
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
/* eliminate trailing . */
|
|
||||||
if(n>=2 && b[n-2]=='/' && b[n-1]=='.')
|
|
||||||
--n;
|
|
||||||
do{
|
|
||||||
/* compress xx/.. */
|
|
||||||
found = FALSE;
|
|
||||||
for(i=1; i<=n-3; i++)
|
|
||||||
if(runeeq(b+i, 3, Lslashdotdot, 3)){
|
|
||||||
if(i==n-3 || b[i+3]=='/'){
|
|
||||||
found = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(found)
|
|
||||||
for(j=i-1; j>=0; --j)
|
|
||||||
if(j==0 || b[j-1]=='/'){
|
|
||||||
i += 3; /* character beyond .. */
|
|
||||||
if(i<n && b[i]=='/')
|
|
||||||
++i;
|
|
||||||
runemove(b+j, b+i, n-i);
|
|
||||||
n -= (i-j);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}while(found);
|
|
||||||
if(n == 0){
|
|
||||||
*b = '.';
|
|
||||||
n = 1;
|
|
||||||
}
|
|
||||||
return (Runestr){b, n};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Runestr
|
Runestr
|
||||||
@ -407,6 +365,11 @@ includename(Text *t, Rune *r, int n)
|
|||||||
Window *w;
|
Window *w;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
Rune Lsysinclude[] = { '/', 's', 'y', 's', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
|
Rune Lsysinclude[] = { '/', 's', 'y', 's', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
|
||||||
|
Rune Lusrinclude[] = { '/', 'u', 's', 'r', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
|
||||||
|
Rune Lusrlocalinclude[] = { '/', 'u', 's', 'r', '/', 'l', 'o', 'c', 'a', 'l',
|
||||||
|
'/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
|
||||||
|
Rune Lusrlocalplan9include[] = { '/', 'u', 's', 'r', '/', 'l', 'o', 'c', 'a', 'l',
|
||||||
|
'/', 'p', 'l', 'a', 'n', '9', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
|
||||||
Runestr file;
|
Runestr file;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -429,6 +392,12 @@ includename(Text *t, Rune *r, int n)
|
|||||||
|
|
||||||
if(file.r == nil)
|
if(file.r == nil)
|
||||||
file = includefile(Lsysinclude, r, n);
|
file = includefile(Lsysinclude, r, n);
|
||||||
|
if(file.r == nil)
|
||||||
|
file = includefile(Lusrlocalplan9include, r, n);
|
||||||
|
if(file.r == nil)
|
||||||
|
file = includefile(Lusrlocalinclude, r, n);
|
||||||
|
if(file.r == nil)
|
||||||
|
file = includefile(Lusrinclude, r, n);
|
||||||
if(file.r==nil && objdir!=nil)
|
if(file.r==nil && objdir!=nil)
|
||||||
file = includefile(objdir, r, n);
|
file = includefile(objdir, r, n);
|
||||||
if(file.r == nil)
|
if(file.r == nil)
|
||||||
@ -702,13 +671,16 @@ openfile(Text *t, Expand *e)
|
|||||||
t->w->dirty = FALSE;
|
t->w->dirty = FALSE;
|
||||||
winsettag(t->w);
|
winsettag(t->w);
|
||||||
textsetselect(&t->w->tag, t->w->tag.file->b.nc, t->w->tag.file->b.nc);
|
textsetselect(&t->w->tag, t->w->tag.file->b.nc, t->w->tag.file->b.nc);
|
||||||
if(ow != nil)
|
if(ow != nil){
|
||||||
for(i=ow->nincl; --i>=0; ){
|
for(i=ow->nincl; --i>=0; ){
|
||||||
n = runestrlen(ow->incl[i]);
|
n = runestrlen(ow->incl[i]);
|
||||||
rp = runemalloc(n);
|
rp = runemalloc(n);
|
||||||
runemove(rp, ow->incl[i], n);
|
runemove(rp, ow->incl[i], n);
|
||||||
winaddincl(w, rp, n);
|
winaddincl(w, rp, n);
|
||||||
}
|
}
|
||||||
|
w->autoindent = ow->autoindent;
|
||||||
|
}else
|
||||||
|
w->autoindent = globalautoindent;
|
||||||
}
|
}
|
||||||
if(e->a1 == e->a0)
|
if(e->a1 == e->a0)
|
||||||
eval = FALSE;
|
eval = FALSE;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
# Acme is up-to-date w.r.t. sources as of 29 February 2004
|
||||||
|
|
||||||
PLAN9=../../..
|
PLAN9=../../..
|
||||||
<$PLAN9/src/mkhdr
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
@ -36,6 +38,6 @@ UPDATE=\
|
|||||||
|
|
||||||
<$PLAN9/src/mkone
|
<$PLAN9/src/mkone
|
||||||
|
|
||||||
LDFLAGS=$LDFLAGS -lcomplete -lplumb -lfs -lmux -lthread -lframe -ldraw -lbio -l9 -lfmt -lutf -L$X11/lib -lX11
|
LDFLAGS=$LDFLAGS -lcomplete -lplumb -lfs -lmux -lthread -lframe -ldraw -lbio -l9 -L$X11/lib -lX11
|
||||||
|
|
||||||
edit.$O ecmd.$O elog.$O: edit.h
|
edit.$O ecmd.$O elog.$O: edit.h
|
||||||
|
|||||||
@ -537,7 +537,7 @@ textfilewidth(Text *t, uint q0, int oneelement)
|
|||||||
q = q0;
|
q = q0;
|
||||||
while(q > 0){
|
while(q > 0){
|
||||||
r = textreadc(t, q-1);
|
r = textreadc(t, q-1);
|
||||||
if(r<=' ')
|
if(r <= ' ')
|
||||||
break;
|
break;
|
||||||
if(oneelement && r=='/')
|
if(oneelement && r=='/')
|
||||||
break;
|
break;
|
||||||
@ -608,10 +608,11 @@ textcomplete(Text *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!c->advance){
|
if(!c->advance){
|
||||||
warning(nil, "%.*S%s%.*S*\n",
|
warning(nil, "%.*S%s%.*S*%s\n",
|
||||||
dir.nr, dir.r,
|
dir.nr, dir.r,
|
||||||
dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "",
|
dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "",
|
||||||
nstr, str);
|
nstr, str,
|
||||||
|
c->nmatch ? "" : ": no matches in:");
|
||||||
for(i=0; i<c->nfile; i++)
|
for(i=0; i<c->nfile; i++)
|
||||||
warning(nil, " %s\n", c->filename[i]);
|
warning(nil, " %s\n", c->filename[i]);
|
||||||
}
|
}
|
||||||
@ -643,25 +644,45 @@ texttype(Text *t, Rune r)
|
|||||||
rp = &r;
|
rp = &r;
|
||||||
switch(r){
|
switch(r){
|
||||||
case Kleft:
|
case Kleft:
|
||||||
if(t->q0 > 0)
|
if(t->q0 > 0){
|
||||||
|
textcommit(t, TRUE);
|
||||||
textshow(t, t->q0-1, t->q0-1, TRUE);
|
textshow(t, t->q0-1, t->q0-1, TRUE);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case Kright:
|
case Kright:
|
||||||
if(t->q1 < t->file->b.nc)
|
if(t->q1 < t->file->b.nc){
|
||||||
|
textcommit(t, TRUE);
|
||||||
textshow(t, t->q1+1, t->q1+1, TRUE);
|
textshow(t, t->q1+1, t->q1+1, TRUE);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case Kdown:
|
case Kdown:
|
||||||
|
n = t->fr.maxlines/3;
|
||||||
|
goto case_Down;
|
||||||
case Kpgdown:
|
case Kpgdown:
|
||||||
n = t->fr.maxlines/2;
|
n = 2*t->fr.maxlines/3;
|
||||||
|
case_Down:
|
||||||
q0 = t->org+frcharofpt(&t->fr, Pt(t->fr.r.min.x, t->fr.r.min.y+n*t->fr.font->height));
|
q0 = t->org+frcharofpt(&t->fr, Pt(t->fr.r.min.x, t->fr.r.min.y+n*t->fr.font->height));
|
||||||
textsetorigin(t, q0, FALSE);
|
textsetorigin(t, q0, FALSE);
|
||||||
return;
|
return;
|
||||||
case Kup:
|
case Kup:
|
||||||
|
n = t->fr.maxlines/3;
|
||||||
|
goto case_Up;
|
||||||
case Kpgup:
|
case Kpgup:
|
||||||
n = t->fr.maxlines/2;
|
n = 2*t->fr.maxlines/3;
|
||||||
|
case_Up:
|
||||||
q0 = textbacknl(t, t->org, n);
|
q0 = textbacknl(t, t->org, n);
|
||||||
textsetorigin(t, q0, FALSE);
|
textsetorigin(t, q0, FALSE);
|
||||||
return;
|
return;
|
||||||
|
case Khome:
|
||||||
|
textshow(t, 0, 0, FALSE);
|
||||||
|
return;
|
||||||
|
case Kend:
|
||||||
|
if(t->w)
|
||||||
|
wincommit(t->w, t);
|
||||||
|
else
|
||||||
|
textcommit(t, TRUE);
|
||||||
|
textshow(t, t->file->b.nc, t->file->b.nc, FALSE);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(t->what == Body){
|
if(t->what == Body){
|
||||||
seq++;
|
seq++;
|
||||||
@ -734,6 +755,21 @@ texttype(Text *t, Rune r)
|
|||||||
for(i=0; i<t->file->ntext; i++)
|
for(i=0; i<t->file->ntext; i++)
|
||||||
textfill(t->file->text[i]);
|
textfill(t->file->text[i]);
|
||||||
return;
|
return;
|
||||||
|
case '\n':
|
||||||
|
if(t->w->autoindent){
|
||||||
|
/* find beginning of previous line using backspace code */
|
||||||
|
nnb = textbswidth(t, 0x15); /* ^U case */
|
||||||
|
rp = runemalloc(nnb + 1);
|
||||||
|
nr = 0;
|
||||||
|
rp[nr++] = r;
|
||||||
|
for(i=0; i<nnb; i++){
|
||||||
|
r = textreadc(t, t->q0-nnb+i);
|
||||||
|
if(r != ' ' && r != '\t')
|
||||||
|
break;
|
||||||
|
rp[nr++] = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break; /* fall through to normal code */
|
||||||
}
|
}
|
||||||
/* otherwise ordinary character; just insert, typically in caches of all texts */
|
/* otherwise ordinary character; just insert, typically in caches of all texts */
|
||||||
for(i=0; i<t->file->ntext; i++){
|
for(i=0; i<t->file->ntext; i++){
|
||||||
|
|||||||
@ -50,7 +50,7 @@ timerproc(void *v)
|
|||||||
nt = 0;
|
nt = 0;
|
||||||
old = msec();
|
old = msec();
|
||||||
for(;;){
|
for(;;){
|
||||||
sleep(1); /* will sleep minimum incr */
|
threadsleep(1); /* will sleep minimum incr */
|
||||||
new = msec();
|
new = msec();
|
||||||
dt = new-old;
|
dt = new-old;
|
||||||
old = new;
|
old = new;
|
||||||
@ -98,7 +98,7 @@ void
|
|||||||
timerinit(void)
|
timerinit(void)
|
||||||
{
|
{
|
||||||
ctimer = chancreate(sizeof(Timer*), 100);
|
ctimer = chancreate(sizeof(Timer*), 100);
|
||||||
proccreate(timerproc, nil, STACK);
|
threadcreate(timerproc, nil, STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer*
|
Timer*
|
||||||
|
|||||||
@ -62,9 +62,11 @@ errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
|
|||||||
int i, n;
|
int i, n;
|
||||||
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
|
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
|
||||||
|
|
||||||
r = runemalloc(ndir+7);
|
r = runemalloc(ndir+8);
|
||||||
if(n = ndir) /* assign = */
|
if(n = ndir){ /* assign = */
|
||||||
runemove(r, dir, ndir);
|
runemove(r, dir, ndir);
|
||||||
|
r[n++] = L'/';
|
||||||
|
}
|
||||||
runemove(r+n, Lpluserrors, 7);
|
runemove(r+n, Lpluserrors, 7);
|
||||||
n += 7;
|
n += 7;
|
||||||
w = lookfile(r, n);
|
w = lookfile(r, n);
|
||||||
@ -83,12 +85,13 @@ errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
|
|||||||
runemove(r, incl[i], n);
|
runemove(r, incl[i], n);
|
||||||
winaddincl(w, r, n);
|
winaddincl(w, r, n);
|
||||||
}
|
}
|
||||||
|
w->autoindent = globalautoindent;
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make new window, if necessary; return with it locked */
|
/* make new window, if necessary; return with it locked */
|
||||||
Window*
|
Window*
|
||||||
errorwin(Mntdir *md, int owner, Window *e)
|
errorwin(Mntdir *md, int owner)
|
||||||
{
|
{
|
||||||
Window *w;
|
Window *w;
|
||||||
|
|
||||||
@ -97,51 +100,100 @@ errorwin(Mntdir *md, int owner, Window *e)
|
|||||||
w = errorwin1(nil, 0, nil, 0);
|
w = errorwin1(nil, 0, nil, 0);
|
||||||
else
|
else
|
||||||
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
|
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
|
||||||
if(w != e)
|
winlock(w, owner);
|
||||||
winlock(w, owner);
|
|
||||||
if(w->col != nil)
|
if(w->col != nil)
|
||||||
break;
|
break;
|
||||||
/* window was deleted too fast */
|
/* window was deleted too fast */
|
||||||
if(w != e)
|
winunlock(w);
|
||||||
winunlock(w);
|
|
||||||
}
|
}
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
typedef struct Warning Warning;
|
||||||
printwarning(Window *ew, Mntdir *md, Rune *r)
|
|
||||||
|
struct Warning{
|
||||||
|
Mntdir *md;
|
||||||
|
Buffer buf;
|
||||||
|
Warning *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Warning *warnings;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
addwarningtext(Mntdir *md, Rune *r, int nr)
|
||||||
{
|
{
|
||||||
int nr, q0, owner;
|
Warning *warn;
|
||||||
|
|
||||||
|
for(warn = warnings; warn; warn=warn->next){
|
||||||
|
if(warn->md == md){
|
||||||
|
bufinsert(&warn->buf, warn->buf.nc, r, nr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warn = emalloc(sizeof(Warning));
|
||||||
|
warn->next = warnings;
|
||||||
|
warnings = warn;
|
||||||
|
bufinsert(&warn->buf, 0, r, nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flushwarnings(int dolock)
|
||||||
|
{
|
||||||
|
Warning *warn, *next;
|
||||||
Window *w;
|
Window *w;
|
||||||
Text *t;
|
Text *t;
|
||||||
|
int owner, nr, q0, n;
|
||||||
|
Rune *r;
|
||||||
|
|
||||||
if(r == nil)
|
if(dolock)
|
||||||
error("runevsmprint failed");
|
qlock(&row.lk);
|
||||||
nr = runestrlen(r);
|
|
||||||
|
|
||||||
if(row.ncol == 0){ /* really early error */
|
if(row.ncol == 0){ /* really early error */
|
||||||
rowinit(&row, screen->clipr);
|
rowinit(&row, screen->clipr);
|
||||||
rowadd(&row, nil, -1);
|
rowadd(&row, nil, -1);
|
||||||
rowadd(&row, nil, -1);
|
rowadd(&row, nil, -1);
|
||||||
if(row.ncol == 0)
|
if(row.ncol == 0)
|
||||||
error("initializing columns in warning()");
|
error("initializing columns in flushwarnings()");
|
||||||
}
|
}
|
||||||
|
|
||||||
w = errorwin(md, 'E', ew);
|
for(warn=warnings; warn; warn=next) {
|
||||||
t = &w->body;
|
w = errorwin(warn->md, 'E');
|
||||||
owner = w->owner;
|
t = &w->body;
|
||||||
if(owner == 0)
|
owner = w->owner;
|
||||||
w->owner = 'E';
|
if(owner == 0)
|
||||||
wincommit(w, t);
|
w->owner = 'E';
|
||||||
q0 = textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
|
wincommit(w, t);
|
||||||
textshow(t, q0, q0+nr, 1);
|
/*
|
||||||
winsettag(t->w);
|
* Most commands don't generate much output. For instance,
|
||||||
textscrdraw(t);
|
* Edit ,>cat goes through /dev/cons and is already in blocks
|
||||||
w->owner = owner;
|
* because of the i/o system, but a few can. Edit ,p will
|
||||||
w->dirty = FALSE;
|
* put the entire result into a single hunk. So it's worth doing
|
||||||
if(ew != w)
|
* this in blocks (and putting the text in a buffer in the first
|
||||||
|
* place), to avoid a big memory footprint.
|
||||||
|
*/
|
||||||
|
r = fbufalloc();
|
||||||
|
q0 = t->file->b.nc;
|
||||||
|
for(n = 0; n < warn->buf.nc; n += nr){
|
||||||
|
nr = warn->buf.nc - n;
|
||||||
|
if(nr > RBUFSIZE)
|
||||||
|
nr = RBUFSIZE;
|
||||||
|
bufread(&warn->buf, n, r, nr);
|
||||||
|
textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
|
||||||
|
}
|
||||||
|
textshow(t, q0, t->file->b.nc, 1);
|
||||||
|
free(r);
|
||||||
|
winsettag(t->w);
|
||||||
|
textscrdraw(t);
|
||||||
|
w->owner = owner;
|
||||||
|
w->dirty = FALSE;
|
||||||
winunlock(w);
|
winunlock(w);
|
||||||
free(r);
|
bufclose(&warn->buf);
|
||||||
|
next = warn->next;
|
||||||
|
free(warn);
|
||||||
|
}
|
||||||
|
warnings = nil;
|
||||||
|
if(dolock)
|
||||||
|
qunlock(&row.lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -153,23 +205,9 @@ warning(Mntdir *md, char *s, ...)
|
|||||||
va_start(arg, s);
|
va_start(arg, s);
|
||||||
r = runevsmprint(s, arg);
|
r = runevsmprint(s, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
printwarning(nil, md, r);
|
if(r == nil)
|
||||||
}
|
error("runevsmprint failed");
|
||||||
|
addwarningtext(md, r, runestrlen(r));
|
||||||
/*
|
|
||||||
* Warningew is like warning but avoids locking the error window
|
|
||||||
* if it's already locked by checking that ew!=error window.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
warningew(Window *ew, Mntdir *md, char *s, ...)
|
|
||||||
{
|
|
||||||
Rune *r;
|
|
||||||
va_list arg;
|
|
||||||
|
|
||||||
va_start(arg, s);
|
|
||||||
r = runevsmprint(s, arg);
|
|
||||||
va_end(arg);
|
|
||||||
printwarning(ew, md, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@ -26,6 +26,8 @@ wininit(Window *w, Window *clone, Rectangle r)
|
|||||||
w->body.w = w;
|
w->body.w = w;
|
||||||
w->id = ++winid;
|
w->id = ++winid;
|
||||||
incref(&w->ref);
|
incref(&w->ref);
|
||||||
|
if(globalincref)
|
||||||
|
incref(&w->ref);
|
||||||
w->ctlfid = ~0;
|
w->ctlfid = ~0;
|
||||||
w->utflastqid = -1;
|
w->utflastqid = -1;
|
||||||
r1 = r;
|
r1 = r;
|
||||||
@ -141,7 +143,7 @@ winlock(Window *w, int owner)
|
|||||||
int i;
|
int i;
|
||||||
File *f;
|
File *f;
|
||||||
|
|
||||||
fprint(2, "winlock %p %d %lux\n", w, owner, getcallerpc(&w));
|
//fprint(2, "winlock %p %d %lux\n", w, owner, getcallerpc(&w));
|
||||||
f = w->body.file;
|
f = w->body.file;
|
||||||
for(i=0; i<f->ntext; i++)
|
for(i=0; i<f->ntext; i++)
|
||||||
winlock1(f->text[i]->w, owner);
|
winlock1(f->text[i]->w, owner);
|
||||||
@ -153,7 +155,7 @@ winunlock(Window *w)
|
|||||||
int i;
|
int i;
|
||||||
File *f;
|
File *f;
|
||||||
|
|
||||||
fprint(2, "winunlock %p %lux\n", w, getcallerpc(&w));
|
//fprint(2, "winunlock %p %lux\n", w, getcallerpc(&w));
|
||||||
f = w->body.file;
|
f = w->body.file;
|
||||||
for(i=0; i<f->ntext; i++){
|
for(i=0; i<f->ntext; i++){
|
||||||
w = f->text[i]->w;
|
w = f->text[i]->w;
|
||||||
|
|||||||
@ -383,7 +383,7 @@ xfidwrite(Xfid *x)
|
|||||||
x->fcall.data[x->fcall.count] = 0;
|
x->fcall.data[x->fcall.count] = 0;
|
||||||
switch(qid){
|
switch(qid){
|
||||||
case Qcons:
|
case Qcons:
|
||||||
w = errorwin(x->f->mntdir, 'X', nil);
|
w = errorwin(x->f->mntdir, 'X');
|
||||||
t=&w->body;
|
t=&w->body;
|
||||||
goto BodyTag;
|
goto BodyTag;
|
||||||
|
|
||||||
@ -543,6 +543,7 @@ xfidwrite(Xfid *x)
|
|||||||
}
|
}
|
||||||
if(w)
|
if(w)
|
||||||
winunlock(w);
|
winunlock(w);
|
||||||
|
flushwarnings(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -813,6 +814,7 @@ xfideventwrite(Xfid *x, Window *w)
|
|||||||
qunlock(&row.lk);
|
qunlock(&row.lk);
|
||||||
goto Rescue;
|
goto Rescue;
|
||||||
}
|
}
|
||||||
|
flushwarnings(0);
|
||||||
qunlock(&row.lk);
|
qunlock(&row.lk);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1030,6 +1032,7 @@ xfidindexread(Xfid *x)
|
|||||||
b[n++] = '\n';
|
b[n++] = '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
flushwarnings(0);
|
||||||
qunlock(&row.lk);
|
qunlock(&row.lk);
|
||||||
off = x->fcall.offset;
|
off = x->fcall.offset;
|
||||||
cnt = x->fcall.count;
|
cnt = x->fcall.count;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ PLAN9=../..
|
|||||||
<$PLAN9/src/mkhdr
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
TARG=`ls *.c | sed 's/\.c//'`
|
TARG=`ls *.c | sed 's/\.c//'`
|
||||||
LDFLAGS=$LDFLAGS -lthread -lsec -lfs -lmux -lregexp9 -lbio -l9 -lfmt -lutf
|
LDFLAGS=$LDFLAGS -lthread -lsec -lfs -lmux -lregexp9 -lbio -l9
|
||||||
|
|
||||||
<$PLAN9/src/mkmany
|
<$PLAN9/src/mkmany
|
||||||
|
|
||||||
|
|||||||
@ -99,10 +99,11 @@ extproc(void *argv)
|
|||||||
c = arg[0];
|
c = arg[0];
|
||||||
fd = (int)arg[1];
|
fd = (int)arg[1];
|
||||||
|
|
||||||
|
threadfdnoblock(fd);
|
||||||
i = 0;
|
i = 0;
|
||||||
for(;;){
|
for(;;){
|
||||||
i = 1-i; /* toggle */
|
i = 1-i; /* toggle */
|
||||||
n = read(fd, plumbbuf[i].data, sizeof plumbbuf[i].data);
|
n = threadread(fd, plumbbuf[i].data, sizeof plumbbuf[i].data);
|
||||||
if(n <= 0){
|
if(n <= 0){
|
||||||
fprint(2, "samterm: extern read error: %r\n");
|
fprint(2, "samterm: extern read error: %r\n");
|
||||||
threadexits("extern"); /* not a fatal error */
|
threadexits("extern"); /* not a fatal error */
|
||||||
@ -165,7 +166,7 @@ extstart(void)
|
|||||||
plumbc = chancreate(sizeof(int), 0);
|
plumbc = chancreate(sizeof(int), 0);
|
||||||
arg[0] = plumbc;
|
arg[0] = plumbc;
|
||||||
arg[1] = (void*)fd;
|
arg[1] = (void*)fd;
|
||||||
proccreate(extproc, arg, STACK);
|
threadcreate(extproc, arg, STACK);
|
||||||
atexit(removeextern);
|
atexit(removeextern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,9 +227,10 @@ plumbproc(void *argv)
|
|||||||
fdp = arg[1];
|
fdp = arg[1];
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
threadfdnoblock(*fdp);
|
||||||
for(;;){
|
for(;;){
|
||||||
i = 1-i; /* toggle */
|
i = 1-i; /* toggle */
|
||||||
n = read(*fdp, plumbbuf[i].data, READBUFSIZE);
|
n = threadread(*fdp, plumbbuf[i].data, READBUFSIZE);
|
||||||
if(n <= 0){
|
if(n <= 0){
|
||||||
fprint(2, "samterm: plumb read error: %r\n");
|
fprint(2, "samterm: plumb read error: %r\n");
|
||||||
threadexits("plumb"); /* not a fatal error */
|
threadexits("plumb"); /* not a fatal error */
|
||||||
@ -258,7 +260,7 @@ plumbstart(void)
|
|||||||
}
|
}
|
||||||
arg[0] =plumbc;
|
arg[0] =plumbc;
|
||||||
arg[1] = &fd;
|
arg[1] = &fd;
|
||||||
proccreate(plumbproc, arg, STACK);
|
threadcreate(plumbproc, arg, STACK);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -278,9 +280,10 @@ hostproc(void *arg)
|
|||||||
c = arg;
|
c = arg;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
threadfdnoblock(hostfd[0]);
|
||||||
for(;;){
|
for(;;){
|
||||||
i = 1-i; /* toggle */
|
i = 1-i; /* toggle */
|
||||||
n = read(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data);
|
n = threadread(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data);
|
||||||
if(n <= 0){
|
if(n <= 0){
|
||||||
fprint(2, "samterm: host read error: %r\n");
|
fprint(2, "samterm: host read error: %r\n");
|
||||||
threadexitsall("host");
|
threadexitsall("host");
|
||||||
@ -295,5 +298,5 @@ void
|
|||||||
hoststart(void)
|
hoststart(void)
|
||||||
{
|
{
|
||||||
hostc = chancreate(sizeof(int), 0);
|
hostc = chancreate(sizeof(int), 0);
|
||||||
proccreate(hostproc, hostc, STACK);
|
threadcreate(hostproc, hostc, STACK);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,8 +71,8 @@ _p9strsig(char *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
await(char *str, int n)
|
_await(char *str, int n, int opt)
|
||||||
{
|
{
|
||||||
int pid, status, cd;
|
int pid, status, cd;
|
||||||
struct rusage ru;
|
struct rusage ru;
|
||||||
@ -80,8 +80,8 @@ await(char *str, int n)
|
|||||||
ulong u, s;
|
ulong u, s;
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
pid = wait3(&status, 0, &ru);
|
pid = wait3(&status, opt, &ru);
|
||||||
if(pid < 0)
|
if(pid <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
|
u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
|
||||||
s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
|
s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
|
||||||
@ -103,3 +103,16 @@ await(char *str, int n)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
await(char *str, int n)
|
||||||
|
{
|
||||||
|
return _await(str, n, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
awaitnohang(char *str, int n)
|
||||||
|
{
|
||||||
|
return _await(str, n, WNOHANG);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,71 @@ PLAN9=../..
|
|||||||
|
|
||||||
LIB=lib9.a
|
LIB=lib9.a
|
||||||
|
|
||||||
|
NUM=\
|
||||||
|
charstod.$O\
|
||||||
|
pow10.$O\
|
||||||
|
|
||||||
|
# Could add errfmt, but we want to pick it up from lib9 instead.
|
||||||
|
FMTOFILES=\
|
||||||
|
dofmt.$O\
|
||||||
|
errfmt.$O\
|
||||||
|
fltfmt.$O\
|
||||||
|
fmt.$O\
|
||||||
|
fmtfd.$O\
|
||||||
|
fmtfdflush.$O\
|
||||||
|
fmtlock.$O\
|
||||||
|
fmtprint.$O\
|
||||||
|
fmtquote.$O\
|
||||||
|
fmtrune.$O\
|
||||||
|
fmtstr.$O\
|
||||||
|
fmtvprint.$O\
|
||||||
|
fprint.$O\
|
||||||
|
nan64.$O\
|
||||||
|
print.$O\
|
||||||
|
runefmtstr.$O\
|
||||||
|
runeseprint.$O\
|
||||||
|
runesmprint.$O\
|
||||||
|
runesnprint.$O\
|
||||||
|
runesprint.$O\
|
||||||
|
runevseprint.$O\
|
||||||
|
runevsmprint.$O\
|
||||||
|
runevsnprint.$O\
|
||||||
|
seprint.$O\
|
||||||
|
smprint.$O\
|
||||||
|
snprint.$O\
|
||||||
|
sprint.$O\
|
||||||
|
strtod.$O\
|
||||||
|
vfprint.$O\
|
||||||
|
vseprint.$O\
|
||||||
|
vsmprint.$O\
|
||||||
|
vsnprint.$O\
|
||||||
|
$NUM\
|
||||||
|
|
||||||
|
UTFOFILES=\
|
||||||
|
rune.$O\
|
||||||
|
runestrcat.$O\
|
||||||
|
runestrchr.$O\
|
||||||
|
runestrcmp.$O\
|
||||||
|
runestrcpy.$O\
|
||||||
|
runestrdup.$O\
|
||||||
|
runestrlen.$O\
|
||||||
|
runestrecpy.$O\
|
||||||
|
runestrncat.$O\
|
||||||
|
runestrncmp.$O\
|
||||||
|
runestrncpy.$O\
|
||||||
|
runestrrchr.$O\
|
||||||
|
runestrstr.$O\
|
||||||
|
runetype.$O\
|
||||||
|
utfecpy.$O\
|
||||||
|
utflen.$O\
|
||||||
|
utfnlen.$O\
|
||||||
|
utfrrune.$O\
|
||||||
|
utfrune.$O\
|
||||||
|
utfutf.$O\
|
||||||
|
|
||||||
OFILES=\
|
OFILES=\
|
||||||
|
$FMTOFILES\
|
||||||
|
$UTFOFILES\
|
||||||
_exits.$O\
|
_exits.$O\
|
||||||
_p9dialparse.$O\
|
_p9dialparse.$O\
|
||||||
_p9dir.$O\
|
_p9dir.$O\
|
||||||
@ -85,3 +149,10 @@ HFILES=\
|
|||||||
$PLAN9/include/lib9.h\
|
$PLAN9/include/lib9.h\
|
||||||
|
|
||||||
<$PLAN9/src/mksyslib
|
<$PLAN9/src/mksyslib
|
||||||
|
|
||||||
|
%.$O: fmt/%.c
|
||||||
|
$CC $CFLAGS -Ifmt fmt/$stem.c
|
||||||
|
|
||||||
|
%.$O: utf/%.c
|
||||||
|
$CC $CFLAGS utf/$stem.c
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include "../libfmt/nan.h"
|
#include "fmt/nan.h"
|
||||||
|
|
||||||
double
|
double
|
||||||
NaN(void)
|
NaN(void)
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
|
|
||||||
Waitmsg*
|
static Waitmsg*
|
||||||
wait(void)
|
_wait(int nohang)
|
||||||
{
|
{
|
||||||
int n, l;
|
int n, l;
|
||||||
char buf[512], *fld[5];
|
char buf[512], *fld[5];
|
||||||
Waitmsg *w;
|
Waitmsg *w;
|
||||||
|
|
||||||
n = await(buf, sizeof buf-1);
|
n = (nohang ? awaitnohang : await)(buf, sizeof buf-1);
|
||||||
if(n < 0)
|
if(n <= 0)
|
||||||
return nil;
|
return nil;
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
||||||
@ -29,3 +29,15 @@ wait(void)
|
|||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Waitmsg*
|
||||||
|
wait(void)
|
||||||
|
{
|
||||||
|
return _wait(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Waitmsg*
|
||||||
|
waitnohang(void)
|
||||||
|
{
|
||||||
|
return _wait(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ strpcmp(const void *va, const void *vb)
|
|||||||
Completion*
|
Completion*
|
||||||
complete(char *dir, char *s)
|
complete(char *dir, char *s)
|
||||||
{
|
{
|
||||||
long i, l, n, nmatch, len, nbytes;
|
long i, l, n, nfile, len, nbytes;
|
||||||
int fd, minlen;
|
int fd, minlen;
|
||||||
Dir *dirp;
|
Dir *dirp;
|
||||||
char **name, *p;
|
char **name, *p;
|
||||||
@ -58,8 +58,10 @@ complete(char *dir, char *s)
|
|||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
n = dirreadall(fd, &dirp);
|
n = dirreadall(fd, &dirp);
|
||||||
if(n <= 0)
|
if(n <= 0){
|
||||||
|
close(fd);
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
/* find longest string, for allocation */
|
/* find longest string, for allocation */
|
||||||
len = 0;
|
len = 0;
|
||||||
@ -78,49 +80,51 @@ complete(char *dir, char *s)
|
|||||||
|
|
||||||
/* find the matches */
|
/* find the matches */
|
||||||
len = strlen(s);
|
len = strlen(s);
|
||||||
nmatch = 0;
|
nfile = 0;
|
||||||
minlen = 1000000;
|
minlen = 1000000;
|
||||||
for(i=0; i<n; i++)
|
for(i=0; i<n; i++)
|
||||||
if(strncmp(s, dirp[i].name, len) == 0){
|
if(strncmp(s, dirp[i].name, len) == 0){
|
||||||
name[nmatch] = dirp[i].name;
|
name[nfile] = dirp[i].name;
|
||||||
mode[nmatch] = dirp[i].mode;
|
mode[nfile] = dirp[i].mode;
|
||||||
if(minlen > strlen(dirp[i].name))
|
if(minlen > strlen(dirp[i].name))
|
||||||
minlen = strlen(dirp[i].name);
|
minlen = strlen(dirp[i].name);
|
||||||
nmatch++;
|
nfile++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nmatch > 0) {
|
if(nfile > 0) {
|
||||||
/* report interesting results */
|
/* report interesting results */
|
||||||
/* trim length back to longest common initial string */
|
/* trim length back to longest common initial string */
|
||||||
for(i=1; i<nmatch; i++)
|
for(i=1; i<nfile; i++)
|
||||||
minlen = longestprefixlength(name[0], name[i], minlen);
|
minlen = longestprefixlength(name[0], name[i], minlen);
|
||||||
|
|
||||||
/* build the answer */
|
/* build the answer */
|
||||||
c->complete = (nmatch == 1);
|
c->complete = (nfile == 1);
|
||||||
c->advance = c->complete || (minlen > len);
|
c->advance = c->complete || (minlen > len);
|
||||||
c->string = (char*)(c+1);
|
c->string = (char*)(c+1);
|
||||||
memmove(c->string, name[0]+len, minlen-len);
|
memmove(c->string, name[0]+len, minlen-len);
|
||||||
if(c->complete)
|
if(c->complete)
|
||||||
c->string[minlen++ - len] = (mode[0]&DMDIR)? '/' : ' ';
|
c->string[minlen++ - len] = (mode[0]&DMDIR)? '/' : ' ';
|
||||||
c->string[minlen - len] = '\0';
|
c->string[minlen - len] = '\0';
|
||||||
|
c->nmatch = nfile;
|
||||||
} else {
|
} else {
|
||||||
/* no match, so return all possible strings */
|
/* no match, so return all possible strings */
|
||||||
for(i=0; i<n; i++){
|
for(i=0; i<n; i++){
|
||||||
name[i] = dirp[i].name;
|
name[i] = dirp[i].name;
|
||||||
mode[i] = dirp[i].mode;
|
mode[i] = dirp[i].mode;
|
||||||
}
|
}
|
||||||
nmatch = n;
|
nfile = n;
|
||||||
|
c->nmatch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* attach list of names */
|
/* attach list of names */
|
||||||
nbytes = nmatch * sizeof(char*);
|
nbytes = nfile * sizeof(char*);
|
||||||
for(i=0; i<nmatch; i++)
|
for(i=0; i<nfile; i++)
|
||||||
nbytes += strlen(name[i]) + 1 + 1;
|
nbytes += strlen(name[i]) + 1 + 1;
|
||||||
c->filename = malloc(nbytes);
|
c->filename = malloc(nbytes);
|
||||||
if(c->filename == nil)
|
if(c->filename == nil)
|
||||||
goto Return;
|
goto Return;
|
||||||
p = (char*)(c->filename + nmatch);
|
p = (char*)(c->filename + nfile);
|
||||||
for(i=0; i<nmatch; i++){
|
for(i=0; i<nfile; i++){
|
||||||
c->filename[i] = p;
|
c->filename[i] = p;
|
||||||
strcpy(p, name[i]);
|
strcpy(p, name[i]);
|
||||||
p += strlen(p);
|
p += strlen(p);
|
||||||
@ -128,12 +132,13 @@ complete(char *dir, char *s)
|
|||||||
*p++ = '/';
|
*p++ = '/';
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
}
|
}
|
||||||
c->nfile = nmatch;
|
c->nfile = nfile;
|
||||||
qsort(c->filename, c->nfile, sizeof(c->filename[0]), strpcmp);
|
qsort(c->filename, c->nfile, sizeof(c->filename[0]), strpcmp);
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
free(name);
|
free(name);
|
||||||
free(mode);
|
free(mode);
|
||||||
free(dirp);
|
free(dirp);
|
||||||
|
close(fd);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -454,7 +454,7 @@ _xselect(XEvent *e, XDisplay *xd)
|
|||||||
|
|
||||||
memset(&r, 0, sizeof r);
|
memset(&r, 0, sizeof r);
|
||||||
xe = (XSelectionRequestEvent*)e;
|
xe = (XSelectionRequestEvent*)e;
|
||||||
if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n",
|
if(1) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n",
|
||||||
xe->target, xe->requestor, xe->property, xe->selection);
|
xe->target, xe->requestor, xe->property, xe->selection);
|
||||||
r.xselection.property = xe->property;
|
r.xselection.property = xe->property;
|
||||||
if(xe->target == _x.targets){
|
if(xe->target == _x.targets){
|
||||||
|
|||||||
@ -34,6 +34,7 @@ void
|
|||||||
_ioproc(void *arg)
|
_ioproc(void *arg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int fd;
|
||||||
Keyboardctl *kc;
|
Keyboardctl *kc;
|
||||||
Rune r;
|
Rune r;
|
||||||
XEvent xevent;
|
XEvent xevent;
|
||||||
@ -41,9 +42,11 @@ _ioproc(void *arg)
|
|||||||
kc = arg;
|
kc = arg;
|
||||||
threadsetname("kbdproc");
|
threadsetname("kbdproc");
|
||||||
kc->pid = getpid();
|
kc->pid = getpid();
|
||||||
|
fd = XConnectionNumber(_x.kbdcon);
|
||||||
XSelectInput(_x.kbdcon, _x.drawable, KeyPressMask);
|
XSelectInput(_x.kbdcon, _x.drawable, KeyPressMask);
|
||||||
for(;;){
|
for(;;){
|
||||||
XWindowEvent(_x.kbdcon, _x.drawable, KeyPressMask, &xevent);
|
while(XCheckWindowEvent(_x.kbdcon, _x.drawable, KeyPressMask, &xevent) == False)
|
||||||
|
threadfdwait(fd, 'r');
|
||||||
switch(xevent.type){
|
switch(xevent.type){
|
||||||
case KeyPress:
|
case KeyPress:
|
||||||
i = _xtoplan9kbd(&xevent);
|
i = _xtoplan9kbd(&xevent);
|
||||||
@ -65,11 +68,12 @@ initkeyboard(char *file)
|
|||||||
{
|
{
|
||||||
Keyboardctl *kc;
|
Keyboardctl *kc;
|
||||||
|
|
||||||
|
threadfdwaitsetup();
|
||||||
kc = mallocz(sizeof(Keyboardctl), 1);
|
kc = mallocz(sizeof(Keyboardctl), 1);
|
||||||
if(kc == nil)
|
if(kc == nil)
|
||||||
return nil;
|
return nil;
|
||||||
kc->c = chancreate(sizeof(Rune), 20);
|
kc->c = chancreate(sizeof(Rune), 20);
|
||||||
proccreate(_ioproc, kc, 4096);
|
threadcreate(_ioproc, kc, 4096);
|
||||||
return kc;
|
return kc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ static
|
|||||||
void
|
void
|
||||||
_ioproc(void *arg)
|
_ioproc(void *arg)
|
||||||
{
|
{
|
||||||
int one;
|
int fd, one;
|
||||||
ulong mask;
|
ulong mask;
|
||||||
Mouse m;
|
Mouse m;
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
@ -60,7 +60,10 @@ _ioproc(void *arg)
|
|||||||
mc->pid = getpid();
|
mc->pid = getpid();
|
||||||
mask = MouseMask|ExposureMask|StructureNotifyMask;
|
mask = MouseMask|ExposureMask|StructureNotifyMask;
|
||||||
XSelectInput(_x.mousecon, _x.drawable, mask);
|
XSelectInput(_x.mousecon, _x.drawable, mask);
|
||||||
|
fd = XConnectionNumber(_x.mousecon);
|
||||||
for(;;){
|
for(;;){
|
||||||
|
while(XPending(_x.mousecon) == False)
|
||||||
|
threadfdwait(fd, 'r');
|
||||||
XNextEvent(_x.mousecon, &xevent);
|
XNextEvent(_x.mousecon, &xevent);
|
||||||
switch(xevent.type){
|
switch(xevent.type){
|
||||||
case Expose:
|
case Expose:
|
||||||
@ -105,12 +108,13 @@ initmouse(char *file, Image *i)
|
|||||||
{
|
{
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
|
|
||||||
|
threadfdwaitsetup();
|
||||||
mc = mallocz(sizeof(Mousectl), 1);
|
mc = mallocz(sizeof(Mousectl), 1);
|
||||||
if(i)
|
if(i)
|
||||||
mc->display = i->display;
|
mc->display = i->display;
|
||||||
mc->c = chancreate(sizeof(Mouse), 0);
|
mc->c = chancreate(sizeof(Mouse), 0);
|
||||||
mc->resizec = chancreate(sizeof(int), 2);
|
mc->resizec = chancreate(sizeof(int), 2);
|
||||||
proccreate(_ioproc, mc, 16384);
|
threadcreate(_ioproc, mc, 16384);
|
||||||
return mc;
|
return mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
This is a Unix port of the Plan 9 formatted I/O package.
|
|
||||||
|
|
||||||
Please send comments about the packaging
|
|
||||||
to Russ Cox <rsc@post.harvard.edu>.
|
|
||||||
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
This is a Unix port of the Plan 9 formatted I/O package.
|
|
||||||
|
|
||||||
Please send comments about the packaging
|
|
||||||
to Russ Cox <rsc@post.harvard.edu>.
|
|
||||||
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
This is a Unix port of the Plan 9 formatted I/O package.
|
|
||||||
|
|
||||||
Please send comments about the packaging
|
|
||||||
to Russ Cox <rsc@post.harvard.edu>.
|
|
||||||
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reads a floating-point number by interpreting successive characters
|
|
||||||
* returned by (*f)(vp). The last call it makes to f terminates the
|
|
||||||
* scan, so is not a character in the number. It may therefore be
|
|
||||||
* necessary to back up the input stream up one byte after calling charstod.
|
|
||||||
*/
|
|
||||||
|
|
||||||
double
|
|
||||||
fmtcharstod(int(*f)(void*), void *vp)
|
|
||||||
{
|
|
||||||
double num, dem;
|
|
||||||
int neg, eneg, dig, exp, c;
|
|
||||||
|
|
||||||
num = 0;
|
|
||||||
neg = 0;
|
|
||||||
dig = 0;
|
|
||||||
exp = 0;
|
|
||||||
eneg = 0;
|
|
||||||
|
|
||||||
c = (*f)(vp);
|
|
||||||
while(c == ' ' || c == '\t')
|
|
||||||
c = (*f)(vp);
|
|
||||||
if(c == '-' || c == '+'){
|
|
||||||
if(c == '-')
|
|
||||||
neg = 1;
|
|
||||||
c = (*f)(vp);
|
|
||||||
}
|
|
||||||
while(c >= '0' && c <= '9'){
|
|
||||||
num = num*10 + c-'0';
|
|
||||||
c = (*f)(vp);
|
|
||||||
}
|
|
||||||
if(c == '.')
|
|
||||||
c = (*f)(vp);
|
|
||||||
while(c >= '0' && c <= '9'){
|
|
||||||
num = num*10 + c-'0';
|
|
||||||
dig++;
|
|
||||||
c = (*f)(vp);
|
|
||||||
}
|
|
||||||
if(c == 'e' || c == 'E'){
|
|
||||||
c = (*f)(vp);
|
|
||||||
if(c == '-' || c == '+'){
|
|
||||||
if(c == '-'){
|
|
||||||
dig = -dig;
|
|
||||||
eneg = 1;
|
|
||||||
}
|
|
||||||
c = (*f)(vp);
|
|
||||||
}
|
|
||||||
while(c >= '0' && c <= '9'){
|
|
||||||
exp = exp*10 + c-'0';
|
|
||||||
c = (*f)(vp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exp -= dig;
|
|
||||||
if(exp < 0){
|
|
||||||
exp = -exp;
|
|
||||||
eneg = !eneg;
|
|
||||||
}
|
|
||||||
dem = __fmtpow10(exp);
|
|
||||||
if(eneg)
|
|
||||||
num /= dem;
|
|
||||||
else
|
|
||||||
num *= dem;
|
|
||||||
if(neg)
|
|
||||||
return -num;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
@ -1,558 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/* format the output into f->to and return the number of characters fmted */
|
|
||||||
int
|
|
||||||
dofmt(Fmt *f, char *fmt)
|
|
||||||
{
|
|
||||||
Rune rune, *rt, *rs;
|
|
||||||
int r;
|
|
||||||
char *t, *s;
|
|
||||||
int n, nfmt;
|
|
||||||
|
|
||||||
nfmt = f->nfmt;
|
|
||||||
for(;;){
|
|
||||||
if(f->runes){
|
|
||||||
rt = (Rune*)f->to;
|
|
||||||
rs = (Rune*)f->stop;
|
|
||||||
while((r = *(uchar*)fmt) && r != '%'){
|
|
||||||
if(r < Runeself)
|
|
||||||
fmt++;
|
|
||||||
else{
|
|
||||||
fmt += chartorune(&rune, fmt);
|
|
||||||
r = rune;
|
|
||||||
}
|
|
||||||
FMTRCHAR(f, rt, rs, r);
|
|
||||||
}
|
|
||||||
fmt++;
|
|
||||||
f->nfmt += rt - (Rune *)f->to;
|
|
||||||
f->to = rt;
|
|
||||||
if(!r)
|
|
||||||
return f->nfmt - nfmt;
|
|
||||||
f->stop = rs;
|
|
||||||
}else{
|
|
||||||
t = (char*)f->to;
|
|
||||||
s = (char*)f->stop;
|
|
||||||
while((r = *(uchar*)fmt) && r != '%'){
|
|
||||||
if(r < Runeself){
|
|
||||||
FMTCHAR(f, t, s, r);
|
|
||||||
fmt++;
|
|
||||||
}else{
|
|
||||||
n = chartorune(&rune, fmt);
|
|
||||||
if(t + n > s){
|
|
||||||
t = (char*)__fmtflush(f, t, n);
|
|
||||||
if(t != nil)
|
|
||||||
s = (char*)f->stop;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
while(n--)
|
|
||||||
*t++ = *fmt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt++;
|
|
||||||
f->nfmt += t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
if(!r)
|
|
||||||
return f->nfmt - nfmt;
|
|
||||||
f->stop = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = (char*)__fmtdispatch(f, fmt, 0);
|
|
||||||
if(fmt == nil)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0; /* not reached */
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
__fmtflush(Fmt *f, void *t, int len)
|
|
||||||
{
|
|
||||||
if(f->runes)
|
|
||||||
f->nfmt += (Rune*)t - (Rune*)f->to;
|
|
||||||
else
|
|
||||||
f->nfmt += (char*)t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
|
|
||||||
f->stop = f->to;
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
return f->to;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* put a formatted block of memory sz bytes long of n runes into the output buffer,
|
|
||||||
* left/right justified in a field of at least f->width charactes
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
__fmtpad(Fmt *f, int n)
|
|
||||||
{
|
|
||||||
char *t, *s;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
t = (char*)f->to;
|
|
||||||
s = (char*)f->stop;
|
|
||||||
for(i = 0; i < n; i++)
|
|
||||||
FMTCHAR(f, t, s, ' ');
|
|
||||||
f->nfmt += t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__rfmtpad(Fmt *f, int n)
|
|
||||||
{
|
|
||||||
Rune *t, *s;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
t = (Rune*)f->to;
|
|
||||||
s = (Rune*)f->stop;
|
|
||||||
for(i = 0; i < n; i++)
|
|
||||||
FMTRCHAR(f, t, s, ' ');
|
|
||||||
f->nfmt += t - (Rune *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__fmtcpy(Fmt *f, const void *vm, int n, int sz)
|
|
||||||
{
|
|
||||||
Rune *rt, *rs, r;
|
|
||||||
char *t, *s, *m, *me;
|
|
||||||
ulong fl;
|
|
||||||
int nc, w;
|
|
||||||
|
|
||||||
m = (char*)vm;
|
|
||||||
me = m + sz;
|
|
||||||
w = f->width;
|
|
||||||
fl = f->flags;
|
|
||||||
if((fl & FmtPrec) && n > f->prec)
|
|
||||||
n = f->prec;
|
|
||||||
if(f->runes){
|
|
||||||
if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
rt = (Rune*)f->to;
|
|
||||||
rs = (Rune*)f->stop;
|
|
||||||
for(nc = n; nc > 0; nc--){
|
|
||||||
r = *(uchar*)m;
|
|
||||||
if(r < Runeself)
|
|
||||||
m++;
|
|
||||||
else if((me - m) >= UTFmax || fullrune(m, me-m))
|
|
||||||
m += chartorune(&r, m);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
FMTRCHAR(f, rt, rs, r);
|
|
||||||
}
|
|
||||||
f->nfmt += rt - (Rune *)f->to;
|
|
||||||
f->to = rt;
|
|
||||||
if(m < me)
|
|
||||||
return -1;
|
|
||||||
if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
}else{
|
|
||||||
if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
t = (char*)f->to;
|
|
||||||
s = (char*)f->stop;
|
|
||||||
for(nc = n; nc > 0; nc--){
|
|
||||||
r = *(uchar*)m;
|
|
||||||
if(r < Runeself)
|
|
||||||
m++;
|
|
||||||
else if((me - m) >= UTFmax || fullrune(m, me-m))
|
|
||||||
m += chartorune(&r, m);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
FMTRUNE(f, t, s, r);
|
|
||||||
}
|
|
||||||
f->nfmt += t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__fmtrcpy(Fmt *f, const void *vm, int n)
|
|
||||||
{
|
|
||||||
Rune r, *m, *me, *rt, *rs;
|
|
||||||
char *t, *s;
|
|
||||||
ulong fl;
|
|
||||||
int w;
|
|
||||||
|
|
||||||
m = (Rune*)vm;
|
|
||||||
w = f->width;
|
|
||||||
fl = f->flags;
|
|
||||||
if((fl & FmtPrec) && n > f->prec)
|
|
||||||
n = f->prec;
|
|
||||||
if(f->runes){
|
|
||||||
if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
rt = (Rune*)f->to;
|
|
||||||
rs = (Rune*)f->stop;
|
|
||||||
for(me = m + n; m < me; m++)
|
|
||||||
FMTRCHAR(f, rt, rs, *m);
|
|
||||||
f->nfmt += rt - (Rune *)f->to;
|
|
||||||
f->to = rt;
|
|
||||||
if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
}else{
|
|
||||||
if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
t = (char*)f->to;
|
|
||||||
s = (char*)f->stop;
|
|
||||||
for(me = m + n; m < me; m++){
|
|
||||||
r = *m;
|
|
||||||
FMTRUNE(f, t, s, r);
|
|
||||||
}
|
|
||||||
f->nfmt += t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmt out one character */
|
|
||||||
int
|
|
||||||
__charfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
char x[1];
|
|
||||||
|
|
||||||
x[0] = va_arg(f->args, int);
|
|
||||||
f->prec = 1;
|
|
||||||
return __fmtcpy(f, (const char*)x, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmt out one rune */
|
|
||||||
int
|
|
||||||
__runefmt(Fmt *f)
|
|
||||||
{
|
|
||||||
Rune x[1];
|
|
||||||
|
|
||||||
x[0] = va_arg(f->args, int);
|
|
||||||
return __fmtrcpy(f, (const void*)x, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* public helper routine: fmt out a null terminated string already in hand */
|
|
||||||
int
|
|
||||||
fmtstrcpy(Fmt *f, char *s)
|
|
||||||
{
|
|
||||||
int p, i;
|
|
||||||
if(!s)
|
|
||||||
return __fmtcpy(f, "<nil>", 5, 5);
|
|
||||||
/* if precision is specified, make sure we don't wander off the end */
|
|
||||||
if(f->flags & FmtPrec){
|
|
||||||
p = f->prec;
|
|
||||||
for(i = 0; i < p; i++)
|
|
||||||
if(s[i] == 0)
|
|
||||||
break;
|
|
||||||
return __fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
|
|
||||||
}
|
|
||||||
|
|
||||||
return __fmtcpy(f, s, utflen(s), strlen(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmt out a null terminated utf string */
|
|
||||||
int
|
|
||||||
__strfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
s = va_arg(f->args, char *);
|
|
||||||
return fmtstrcpy(f, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* public helper routine: fmt out a null terminated rune string already in hand */
|
|
||||||
int
|
|
||||||
fmtrunestrcpy(Fmt *f, Rune *s)
|
|
||||||
{
|
|
||||||
Rune *e;
|
|
||||||
int n, p;
|
|
||||||
|
|
||||||
if(!s)
|
|
||||||
return __fmtcpy(f, "<nil>", 5, 5);
|
|
||||||
/* if precision is specified, make sure we don't wander off the end */
|
|
||||||
if(f->flags & FmtPrec){
|
|
||||||
p = f->prec;
|
|
||||||
for(n = 0; n < p; n++)
|
|
||||||
if(s[n] == 0)
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
for(e = s; *e; e++)
|
|
||||||
;
|
|
||||||
n = e - s;
|
|
||||||
}
|
|
||||||
return __fmtrcpy(f, s, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmt out a null terminated rune string */
|
|
||||||
int
|
|
||||||
__runesfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
Rune *s;
|
|
||||||
|
|
||||||
s = va_arg(f->args, Rune *);
|
|
||||||
return fmtrunestrcpy(f, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmt a % */
|
|
||||||
int
|
|
||||||
__percentfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
Rune x[1];
|
|
||||||
|
|
||||||
x[0] = f->r;
|
|
||||||
f->prec = 1;
|
|
||||||
return __fmtrcpy(f, (const void*)x, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fmt an integer */
|
|
||||||
int
|
|
||||||
__ifmt(Fmt *f)
|
|
||||||
{
|
|
||||||
char buf[70], *p, *conv;
|
|
||||||
uvlong vu;
|
|
||||||
ulong u;
|
|
||||||
int neg, base, i, n, fl, w, isv;
|
|
||||||
|
|
||||||
neg = 0;
|
|
||||||
fl = f->flags;
|
|
||||||
isv = 0;
|
|
||||||
vu = 0;
|
|
||||||
u = 0;
|
|
||||||
/*
|
|
||||||
* Unsigned verbs
|
|
||||||
*/
|
|
||||||
switch(f->r){
|
|
||||||
case 'o':
|
|
||||||
case 'u':
|
|
||||||
case 'x':
|
|
||||||
case 'X':
|
|
||||||
fl |= FmtUnsigned;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(f->r == 'p'){
|
|
||||||
u = (ulong)va_arg(f->args, void*);
|
|
||||||
f->r = 'x';
|
|
||||||
fl |= FmtUnsigned;
|
|
||||||
}else if(fl & FmtVLong){
|
|
||||||
isv = 1;
|
|
||||||
if(fl & FmtUnsigned)
|
|
||||||
vu = va_arg(f->args, uvlong);
|
|
||||||
else
|
|
||||||
vu = va_arg(f->args, vlong);
|
|
||||||
}else if(fl & FmtLong){
|
|
||||||
if(fl & FmtUnsigned)
|
|
||||||
u = va_arg(f->args, ulong);
|
|
||||||
else
|
|
||||||
u = va_arg(f->args, long);
|
|
||||||
}else if(fl & FmtByte){
|
|
||||||
if(fl & FmtUnsigned)
|
|
||||||
u = (uchar)va_arg(f->args, int);
|
|
||||||
else
|
|
||||||
u = (char)va_arg(f->args, int);
|
|
||||||
}else if(fl & FmtShort){
|
|
||||||
if(fl & FmtUnsigned)
|
|
||||||
u = (ushort)va_arg(f->args, int);
|
|
||||||
else
|
|
||||||
u = (short)va_arg(f->args, int);
|
|
||||||
}else{
|
|
||||||
if(fl & FmtUnsigned)
|
|
||||||
u = va_arg(f->args, uint);
|
|
||||||
else
|
|
||||||
u = va_arg(f->args, int);
|
|
||||||
}
|
|
||||||
conv = "0123456789abcdef";
|
|
||||||
switch(f->r){
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
base = 10;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
base = 10;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
base = 16;
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
base = 16;
|
|
||||||
conv = "0123456789ABCDEF";
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
base = 2;
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
base = 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(!(fl & FmtUnsigned)){
|
|
||||||
if(isv && (vlong)vu < 0){
|
|
||||||
vu = -(vlong)vu;
|
|
||||||
neg = 1;
|
|
||||||
}else if(!isv && (long)u < 0){
|
|
||||||
u = -(long)u;
|
|
||||||
neg = 1;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
fl &= ~(FmtSign|FmtSpace); /* no + for unsigned conversions */
|
|
||||||
}
|
|
||||||
p = buf + sizeof buf - 1;
|
|
||||||
n = 0;
|
|
||||||
if(isv){
|
|
||||||
while(vu){
|
|
||||||
i = vu % base;
|
|
||||||
vu /= base;
|
|
||||||
if((fl & FmtComma) && n % 4 == 3){
|
|
||||||
*p-- = ',';
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
*p-- = conv[i];
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
while(u){
|
|
||||||
i = u % base;
|
|
||||||
u /= base;
|
|
||||||
if((fl & FmtComma) && n % 4 == 3){
|
|
||||||
*p-- = ',';
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
*p-- = conv[i];
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(n == 0){
|
|
||||||
if(!(fl & FmtPrec) || f->prec != 0){
|
|
||||||
*p-- = '0';
|
|
||||||
n = 1;
|
|
||||||
}
|
|
||||||
fl &= ~FmtSharp;
|
|
||||||
}
|
|
||||||
for(w = f->prec; n < w && p > buf+3; n++)
|
|
||||||
*p-- = '0';
|
|
||||||
if(neg || (fl & (FmtSign|FmtSpace)))
|
|
||||||
n++;
|
|
||||||
if(fl & FmtSharp){
|
|
||||||
if(base == 16)
|
|
||||||
n += 2;
|
|
||||||
else if(base == 8){
|
|
||||||
if(p[1] == '0')
|
|
||||||
fl &= ~FmtSharp;
|
|
||||||
else
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
|
|
||||||
for(w = f->width; n < w && p > buf+3; n++)
|
|
||||||
*p-- = '0';
|
|
||||||
f->width = 0;
|
|
||||||
}
|
|
||||||
if(fl & FmtSharp){
|
|
||||||
if(base == 16)
|
|
||||||
*p-- = f->r;
|
|
||||||
if(base == 16 || base == 8)
|
|
||||||
*p-- = '0';
|
|
||||||
}
|
|
||||||
if(neg)
|
|
||||||
*p-- = '-';
|
|
||||||
else if(fl & FmtSign)
|
|
||||||
*p-- = '+';
|
|
||||||
else if(fl & FmtSpace)
|
|
||||||
*p-- = ' ';
|
|
||||||
f->flags &= ~FmtPrec;
|
|
||||||
return __fmtcpy(f, p + 1, n, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__countfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
ulong fl;
|
|
||||||
|
|
||||||
fl = f->flags;
|
|
||||||
p = va_arg(f->args, void*);
|
|
||||||
if(fl & FmtVLong){
|
|
||||||
*(vlong*)p = f->nfmt;
|
|
||||||
}else if(fl & FmtLong){
|
|
||||||
*(long*)p = f->nfmt;
|
|
||||||
}else if(fl & FmtByte){
|
|
||||||
*(char*)p = f->nfmt;
|
|
||||||
}else if(fl & FmtShort){
|
|
||||||
*(short*)p = f->nfmt;
|
|
||||||
}else{
|
|
||||||
*(int*)p = f->nfmt;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__flagfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
switch(f->r){
|
|
||||||
case ',':
|
|
||||||
f->flags |= FmtComma;
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
f->flags |= FmtLeft;
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
f->flags |= FmtSign;
|
|
||||||
break;
|
|
||||||
case '#':
|
|
||||||
f->flags |= FmtSharp;
|
|
||||||
break;
|
|
||||||
case ' ':
|
|
||||||
f->flags |= FmtSpace;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
f->flags |= FmtUnsigned;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
if(f->flags & FmtShort)
|
|
||||||
f->flags |= FmtByte;
|
|
||||||
f->flags |= FmtShort;
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
f->flags |= FmtLDouble;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
if(f->flags & FmtLong)
|
|
||||||
f->flags |= FmtVLong;
|
|
||||||
f->flags |= FmtLong;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* default error format */
|
|
||||||
int
|
|
||||||
__badfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
char x[3];
|
|
||||||
|
|
||||||
x[0] = '%';
|
|
||||||
x[1] = f->r;
|
|
||||||
x[2] = '%';
|
|
||||||
f->prec = 3;
|
|
||||||
__fmtcpy(f, (const void*)x, 3, 3);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/* format the output into f->to and return the number of characters fmted */
|
|
||||||
|
|
||||||
int
|
|
||||||
dorfmt(Fmt *f, const Rune *fmt)
|
|
||||||
{
|
|
||||||
Rune *rt, *rs;
|
|
||||||
int r;
|
|
||||||
char *t, *s;
|
|
||||||
int nfmt;
|
|
||||||
|
|
||||||
nfmt = f->nfmt;
|
|
||||||
for(;;){
|
|
||||||
if(f->runes){
|
|
||||||
rt = f->to;
|
|
||||||
rs = f->stop;
|
|
||||||
while((r = *fmt++) && r != '%'){
|
|
||||||
FMTRCHAR(f, rt, rs, r);
|
|
||||||
}
|
|
||||||
f->nfmt += rt - (Rune *)f->to;
|
|
||||||
f->to = rt;
|
|
||||||
if(!r)
|
|
||||||
return f->nfmt - nfmt;
|
|
||||||
f->stop = rs;
|
|
||||||
}else{
|
|
||||||
t = f->to;
|
|
||||||
s = f->stop;
|
|
||||||
while((r = *fmt++) && r != '%'){
|
|
||||||
FMTRUNE(f, t, f->stop, r);
|
|
||||||
}
|
|
||||||
f->nfmt += t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
if(!r)
|
|
||||||
return f->nfmt - nfmt;
|
|
||||||
f->stop = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = __fmtdispatch(f, fmt, 1);
|
|
||||||
if(fmt == nil)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0; /* not reached */
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
__errfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
s = strerror(errno);
|
|
||||||
return fmtstrcpy(f, s);
|
|
||||||
}
|
|
||||||
@ -1,610 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <float.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
#include "nan.h"
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
FDEFLT = 6,
|
|
||||||
NSIGNIF = 17
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* first few powers of 10, enough for about 1/2 of the
|
|
||||||
* total space for doubles.
|
|
||||||
*/
|
|
||||||
static double pows10[] =
|
|
||||||
{
|
|
||||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
|
||||||
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
|
||||||
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
|
|
||||||
1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
|
|
||||||
1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
|
|
||||||
1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
|
|
||||||
1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
|
|
||||||
1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
|
|
||||||
1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
|
|
||||||
1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
|
|
||||||
1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
|
|
||||||
1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
|
|
||||||
1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
|
|
||||||
1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
|
|
||||||
1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
|
|
||||||
1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
|
|
||||||
};
|
|
||||||
|
|
||||||
static double
|
|
||||||
pow10(int n)
|
|
||||||
{
|
|
||||||
double d;
|
|
||||||
int neg;
|
|
||||||
|
|
||||||
neg = 0;
|
|
||||||
if(n < 0){
|
|
||||||
if(n < DBL_MIN_10_EXP){
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
neg = 1;
|
|
||||||
n = -n;
|
|
||||||
}else if(n > DBL_MAX_10_EXP){
|
|
||||||
return HUGE_VAL;
|
|
||||||
}
|
|
||||||
if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
|
|
||||||
d = pows10[n];
|
|
||||||
else{
|
|
||||||
d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
|
|
||||||
for(;;){
|
|
||||||
n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
|
|
||||||
if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
|
|
||||||
d *= pows10[n];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(neg){
|
|
||||||
return 1./d;
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
xadd(char *a, int n, int v)
|
|
||||||
{
|
|
||||||
char *b;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
if(n < 0 || n >= NSIGNIF)
|
|
||||||
return 0;
|
|
||||||
for(b = a+n; b >= a; b--) {
|
|
||||||
c = *b + v;
|
|
||||||
if(c <= '9') {
|
|
||||||
*b = c;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*b = '0';
|
|
||||||
v = 1;
|
|
||||||
}
|
|
||||||
*a = '1'; /* overflow adding */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
xsub(char *a, int n, int v)
|
|
||||||
{
|
|
||||||
char *b;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
for(b = a+n; b >= a; b--) {
|
|
||||||
c = *b - v;
|
|
||||||
if(c >= '0') {
|
|
||||||
*b = c;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*b = '9';
|
|
||||||
v = 1;
|
|
||||||
}
|
|
||||||
*a = '9'; /* underflow subtracting */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
xaddexp(char *p, int e)
|
|
||||||
{
|
|
||||||
char se[9];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
*p++ = 'e';
|
|
||||||
if(e < 0) {
|
|
||||||
*p++ = '-';
|
|
||||||
e = -e;
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
while(e) {
|
|
||||||
se[i++] = e % 10 + '0';
|
|
||||||
e /= 10;
|
|
||||||
}
|
|
||||||
if(i == 0) {
|
|
||||||
*p++ = '0';
|
|
||||||
} else {
|
|
||||||
while(i > 0)
|
|
||||||
*p++ = se[--i];
|
|
||||||
}
|
|
||||||
*p++ = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
xdodtoa(char *s1, double f, int chr, int prec, int *decpt, int *rsign)
|
|
||||||
{
|
|
||||||
char s2[NSIGNIF+10];
|
|
||||||
double g, h;
|
|
||||||
int e, d, i;
|
|
||||||
int c2, sign, oerr;
|
|
||||||
|
|
||||||
if(chr == 'F')
|
|
||||||
chr = 'f';
|
|
||||||
if(prec > NSIGNIF)
|
|
||||||
prec = NSIGNIF;
|
|
||||||
if(prec < 0)
|
|
||||||
prec = 0;
|
|
||||||
if(__isNaN(f)) {
|
|
||||||
*decpt = 9999;
|
|
||||||
*rsign = 0;
|
|
||||||
strcpy(s1, "nan");
|
|
||||||
return &s1[3];
|
|
||||||
}
|
|
||||||
sign = 0;
|
|
||||||
if(f < 0) {
|
|
||||||
f = -f;
|
|
||||||
sign++;
|
|
||||||
}
|
|
||||||
*rsign = sign;
|
|
||||||
if(__isInf(f, 1) || __isInf(f, -1)) {
|
|
||||||
*decpt = 9999;
|
|
||||||
strcpy(s1, "inf");
|
|
||||||
return &s1[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
e = 0;
|
|
||||||
g = f;
|
|
||||||
if(g != 0) {
|
|
||||||
frexp(f, &e);
|
|
||||||
e = (int)(e * .301029995664);
|
|
||||||
if(e >= -150 && e <= +150) {
|
|
||||||
d = 0;
|
|
||||||
h = f;
|
|
||||||
} else {
|
|
||||||
d = e/2;
|
|
||||||
h = f * pow10(-d);
|
|
||||||
}
|
|
||||||
g = h * pow10(d-e);
|
|
||||||
while(g < 1) {
|
|
||||||
e--;
|
|
||||||
g = h * pow10(d-e);
|
|
||||||
}
|
|
||||||
while(g >= 10) {
|
|
||||||
e++;
|
|
||||||
g = h * pow10(d-e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* convert NSIGNIF digits and convert
|
|
||||||
* back to get accuracy.
|
|
||||||
*/
|
|
||||||
for(i=0; i<NSIGNIF; i++) {
|
|
||||||
d = (int)g;
|
|
||||||
s1[i] = d + '0';
|
|
||||||
g = (g - d) * 10;
|
|
||||||
}
|
|
||||||
s1[i] = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* try decimal rounding to eliminate 9s
|
|
||||||
*/
|
|
||||||
c2 = prec + 1;
|
|
||||||
if(chr == 'f')
|
|
||||||
c2 += e;
|
|
||||||
oerr = errno;
|
|
||||||
if(c2 >= NSIGNIF-2) {
|
|
||||||
strcpy(s2, s1);
|
|
||||||
d = e;
|
|
||||||
s1[NSIGNIF-2] = '0';
|
|
||||||
s1[NSIGNIF-1] = '0';
|
|
||||||
xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
|
|
||||||
g = fmtstrtod(s1, nil);
|
|
||||||
if(g == f)
|
|
||||||
goto found;
|
|
||||||
if(xadd(s1, NSIGNIF-3, 1)) {
|
|
||||||
e++;
|
|
||||||
xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
|
|
||||||
}
|
|
||||||
g = fmtstrtod(s1, nil);
|
|
||||||
if(g == f)
|
|
||||||
goto found;
|
|
||||||
strcpy(s1, s2);
|
|
||||||
e = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* convert back so s1 gets exact answer
|
|
||||||
*/
|
|
||||||
for(d = 0; d < 10; d++) {
|
|
||||||
xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
|
|
||||||
g = fmtstrtod(s1, nil);
|
|
||||||
if(f > g) {
|
|
||||||
if(xadd(s1, NSIGNIF-1, 1))
|
|
||||||
e--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(f < g) {
|
|
||||||
if(xsub(s1, NSIGNIF-1, 1))
|
|
||||||
e++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
found:
|
|
||||||
errno = oerr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sign
|
|
||||||
*/
|
|
||||||
d = 0;
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* round & adjust 'f' digits
|
|
||||||
*/
|
|
||||||
c2 = prec + 1;
|
|
||||||
if(chr == 'f'){
|
|
||||||
if(xadd(s1, c2+e, 5))
|
|
||||||
e++;
|
|
||||||
c2 += e;
|
|
||||||
if(c2 < 0){
|
|
||||||
c2 = 0;
|
|
||||||
e = -prec - 1;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
if(xadd(s1, c2, 5))
|
|
||||||
e++;
|
|
||||||
}
|
|
||||||
if(c2 > NSIGNIF){
|
|
||||||
c2 = NSIGNIF;
|
|
||||||
}
|
|
||||||
|
|
||||||
*decpt = e + 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* terminate the converted digits
|
|
||||||
*/
|
|
||||||
s1[c2] = '\0';
|
|
||||||
return &s1[c2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this function works like the standard dtoa, if you want it.
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
static char*
|
|
||||||
__dtoa(double f, int mode, int ndigits, int *decpt, int *rsign, char **rve)
|
|
||||||
{
|
|
||||||
static char s2[NSIGNIF + 10];
|
|
||||||
char *es;
|
|
||||||
int chr, prec;
|
|
||||||
|
|
||||||
switch(mode) {
|
|
||||||
/* like 'e' */
|
|
||||||
case 2:
|
|
||||||
case 4:
|
|
||||||
case 6:
|
|
||||||
case 8:
|
|
||||||
chr = 'e';
|
|
||||||
break;
|
|
||||||
/* like 'g' */
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
default:
|
|
||||||
chr = 'g';
|
|
||||||
break;
|
|
||||||
/* like 'f' */
|
|
||||||
case 3:
|
|
||||||
case 5:
|
|
||||||
case 7:
|
|
||||||
case 9:
|
|
||||||
chr = 'f';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(chr != 'f' && ndigits){
|
|
||||||
ndigits--;
|
|
||||||
}
|
|
||||||
prec = ndigits;
|
|
||||||
if(prec > NSIGNIF)
|
|
||||||
prec = NSIGNIF;
|
|
||||||
if(ndigits == 0)
|
|
||||||
prec = NSIGNIF;
|
|
||||||
es = xdodtoa(s2, f, chr, prec, decpt, rsign);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* strip trailing 0
|
|
||||||
*/
|
|
||||||
for(; es > s2 + 1; es--){
|
|
||||||
if(es[-1] != '0'){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*es = '\0';
|
|
||||||
if(rve != NULL)
|
|
||||||
*rve = es;
|
|
||||||
return s2;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
|
||||||
fmtzdotpad(Fmt *f, int n, int pt)
|
|
||||||
{
|
|
||||||
char *t, *s;
|
|
||||||
int i;
|
|
||||||
Rune *rt, *rs;
|
|
||||||
|
|
||||||
if(f->runes){
|
|
||||||
rt = (Rune*)f->to;
|
|
||||||
rs = (Rune*)f->stop;
|
|
||||||
for(i = 0; i < n; i++){
|
|
||||||
if(i == pt){
|
|
||||||
FMTRCHAR(f, rt, rs, '.');
|
|
||||||
}
|
|
||||||
FMTRCHAR(f, rt, rs, '0');
|
|
||||||
}
|
|
||||||
f->nfmt += rt - (Rune*)f->to;
|
|
||||||
f->to = rt;
|
|
||||||
}else{
|
|
||||||
t = (char*)f->to;
|
|
||||||
s = (char*)f->stop;
|
|
||||||
for(i = 0; i < n; i++){
|
|
||||||
if(i == pt){
|
|
||||||
FMTCHAR(f, t, s, '.');
|
|
||||||
}
|
|
||||||
FMTCHAR(f, t, s, '0');
|
|
||||||
}
|
|
||||||
f->nfmt += t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__efgfmt(Fmt *fmt)
|
|
||||||
{
|
|
||||||
double f;
|
|
||||||
char s1[NSIGNIF+10];
|
|
||||||
int e, d, n;
|
|
||||||
int c1, c2, c3, c4, ucase, sign, chr, prec, fl;
|
|
||||||
|
|
||||||
f = va_arg(fmt->args, double);
|
|
||||||
prec = FDEFLT;
|
|
||||||
fl = fmt->flags;
|
|
||||||
fmt->flags = 0;
|
|
||||||
if(fl & FmtPrec)
|
|
||||||
prec = fmt->prec;
|
|
||||||
chr = fmt->r;
|
|
||||||
ucase = 0;
|
|
||||||
if(chr == 'E'){
|
|
||||||
chr = 'e';
|
|
||||||
ucase = 1;
|
|
||||||
}else if(chr == 'F'){
|
|
||||||
chr = 'f';
|
|
||||||
ucase = 1;
|
|
||||||
}else if(chr == 'G'){
|
|
||||||
chr = 'g';
|
|
||||||
ucase = 1;
|
|
||||||
}
|
|
||||||
if(prec > 0 && chr == 'g')
|
|
||||||
prec--;
|
|
||||||
if(prec < 0)
|
|
||||||
prec = 0;
|
|
||||||
|
|
||||||
xdodtoa(s1, f, chr, prec, &e, &sign);
|
|
||||||
e--;
|
|
||||||
if(*s1 == 'i' || *s1 == 'n'){
|
|
||||||
if(ucase){
|
|
||||||
if(*s1 == 'i'){
|
|
||||||
strcpy(s1, "INF");
|
|
||||||
}else{
|
|
||||||
strcpy(s1, "NAN");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt->flags = fl & (FmtWidth|FmtLeft);
|
|
||||||
return __fmtcpy(fmt, (const void*)s1, 3, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* copy into final place
|
|
||||||
* c1 digits of leading '0'
|
|
||||||
* c2 digits from conversion
|
|
||||||
* c3 digits of trailing '0'
|
|
||||||
* c4 digits after '.'
|
|
||||||
*/
|
|
||||||
c1 = 0;
|
|
||||||
c2 = prec + 1;
|
|
||||||
c3 = 0;
|
|
||||||
c4 = prec;
|
|
||||||
switch(chr) {
|
|
||||||
default:
|
|
||||||
chr = 'e';
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
/*
|
|
||||||
* decide on 'e' of 'f' style convers
|
|
||||||
*/
|
|
||||||
if(e >= -4 && e <= prec) {
|
|
||||||
c1 = -e;
|
|
||||||
c4 = prec - e;
|
|
||||||
chr = 'h'; /* flag for 'f' style */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
c1 = -e;
|
|
||||||
if(c1 > prec)
|
|
||||||
c1 = prec + 1;
|
|
||||||
c2 += e;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clean up c1 c2 and c3
|
|
||||||
*/
|
|
||||||
if(c1 < 0)
|
|
||||||
c1 = 0;
|
|
||||||
if(c2 < 0)
|
|
||||||
c2 = 0;
|
|
||||||
if(c2 > NSIGNIF) {
|
|
||||||
c3 = c2-NSIGNIF;
|
|
||||||
c2 = NSIGNIF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* trim trailing zeros for %g
|
|
||||||
*/
|
|
||||||
if(!(fl & FmtSharp)
|
|
||||||
&& (chr == 'g' || chr == 'h')){
|
|
||||||
if(c4 >= c3){
|
|
||||||
c4 -= c3;
|
|
||||||
c3 = 0;
|
|
||||||
}else{
|
|
||||||
c3 -= c4;
|
|
||||||
c4 = 0;
|
|
||||||
}
|
|
||||||
while(c4 && c2 > 1 && s1[c2 - 1] == '0'){
|
|
||||||
c4--;
|
|
||||||
c2--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* calculate the total length
|
|
||||||
*/
|
|
||||||
n = c1 + c2 + c3;
|
|
||||||
if(sign || (fl & (FmtSign|FmtSpace)))
|
|
||||||
n++;
|
|
||||||
if(c4 || (fl & FmtSharp)){
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
if(chr == 'e' || chr == 'g'){
|
|
||||||
n += 4;
|
|
||||||
if(e >= 100)
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pad to width if right justified
|
|
||||||
*/
|
|
||||||
if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){
|
|
||||||
if(fl & FmtZero){
|
|
||||||
c1 += fmt->width - n;
|
|
||||||
}else{
|
|
||||||
if(__fmtpad(fmt, fmt->width - n) < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sign
|
|
||||||
*/
|
|
||||||
d = 0;
|
|
||||||
if(sign)
|
|
||||||
d = '-';
|
|
||||||
else if(fl & FmtSign)
|
|
||||||
d = '+';
|
|
||||||
else if(fl & FmtSpace)
|
|
||||||
d = ' ';
|
|
||||||
if(d && fmtrune(fmt, d) < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* copy digits
|
|
||||||
*/
|
|
||||||
c4 = c1 + c2 + c3 - c4;
|
|
||||||
if(c1 > 0){
|
|
||||||
if(fmtzdotpad(fmt, c1, c4) < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
c4 -= c1;
|
|
||||||
}
|
|
||||||
d = 0;
|
|
||||||
if(c4 >= 0 && c4 < c2){
|
|
||||||
if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0)
|
|
||||||
return -1;
|
|
||||||
d = c4;
|
|
||||||
c2 -= c4;
|
|
||||||
c4 = -1;
|
|
||||||
}
|
|
||||||
if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
c4 -= c2;
|
|
||||||
if(c3 > 0){
|
|
||||||
if(fmtzdotpad(fmt, c3, c4) < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
c4 -= c3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* strip trailing '0' on g conv
|
|
||||||
*/
|
|
||||||
if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(chr == 'e' || chr == 'g') {
|
|
||||||
d = 0;
|
|
||||||
if(ucase)
|
|
||||||
s1[d++] = 'E';
|
|
||||||
else
|
|
||||||
s1[d++] = 'e';
|
|
||||||
c1 = e;
|
|
||||||
if(c1 < 0) {
|
|
||||||
s1[d++] = '-';
|
|
||||||
c1 = -c1;
|
|
||||||
} else
|
|
||||||
s1[d++] = '+';
|
|
||||||
if(c1 >= 100) {
|
|
||||||
s1[d++] = c1/100 + '0';
|
|
||||||
c1 = c1%100;
|
|
||||||
}
|
|
||||||
s1[d++] = c1/10 + '0';
|
|
||||||
s1[d++] = c1%10 + '0';
|
|
||||||
if(__fmtcpy(fmt, s1, d, d) < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){
|
|
||||||
if(__fmtpad(fmt, fmt->width - n) < 0){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
221
src/libfmt/fmt.c
221
src/libfmt/fmt.c
@ -1,221 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
Maxfmt = 64
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Convfmt Convfmt;
|
|
||||||
struct Convfmt
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/* lock by calling __fmtlock, __fmtunlock */
|
|
||||||
int nfmt;
|
|
||||||
Convfmt fmt[Maxfmt];
|
|
||||||
} fmtalloc;
|
|
||||||
|
|
||||||
static Convfmt knownfmt[] = {
|
|
||||||
' ', __flagfmt,
|
|
||||||
'#', __flagfmt,
|
|
||||||
'%', __percentfmt,
|
|
||||||
'+', __flagfmt,
|
|
||||||
',', __flagfmt,
|
|
||||||
'-', __flagfmt,
|
|
||||||
'C', __runefmt, /* Plan 9 addition */
|
|
||||||
'E', __efgfmt,
|
|
||||||
'F', __efgfmt, /* ANSI only */
|
|
||||||
'G', __efgfmt,
|
|
||||||
'L', __flagfmt, /* ANSI only */
|
|
||||||
'S', __runesfmt, /* Plan 9 addition */
|
|
||||||
'X', __ifmt,
|
|
||||||
'b', __ifmt, /* Plan 9 addition */
|
|
||||||
'c', __charfmt,
|
|
||||||
'd', __ifmt,
|
|
||||||
'e', __efgfmt,
|
|
||||||
'f', __efgfmt,
|
|
||||||
'g', __efgfmt,
|
|
||||||
'h', __flagfmt,
|
|
||||||
'i', __ifmt, /* ANSI only */
|
|
||||||
'l', __flagfmt,
|
|
||||||
'n', __countfmt,
|
|
||||||
'o', __ifmt,
|
|
||||||
'p', __ifmt,
|
|
||||||
'r', __errfmt,
|
|
||||||
's', __strfmt,
|
|
||||||
'u', __flagfmt, /* in Unix, __ifmt */
|
|
||||||
'x', __ifmt,
|
|
||||||
0, nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int (*fmtdoquote)(int);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* __fmtlock() must be set
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
__fmtinstall(int c, Fmts f)
|
|
||||||
{
|
|
||||||
Convfmt *p, *ep;
|
|
||||||
|
|
||||||
if(c<=0 || c>=65536)
|
|
||||||
return -1;
|
|
||||||
if(!f)
|
|
||||||
f = __badfmt;
|
|
||||||
|
|
||||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
|
||||||
for(p=fmtalloc.fmt; p<ep; p++)
|
|
||||||
if(p->c == c)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(p == &fmtalloc.fmt[Maxfmt])
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
p->fmt = f;
|
|
||||||
if(p == ep){ /* installing a new format character */
|
|
||||||
fmtalloc.nfmt++;
|
|
||||||
p->c = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fmtinstall(int c, Fmts f)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
__fmtlock();
|
|
||||||
ret = __fmtinstall(c, f);
|
|
||||||
__fmtunlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Fmts
|
|
||||||
fmtfmt(int c)
|
|
||||||
{
|
|
||||||
Convfmt *p, *ep;
|
|
||||||
|
|
||||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
|
||||||
for(p=fmtalloc.fmt; p<ep; p++)
|
|
||||||
if(p->c == c){
|
|
||||||
while(p->fmt == nil) /* loop until value is updated */
|
|
||||||
;
|
|
||||||
return p->fmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* is this a predefined format char? */
|
|
||||||
__fmtlock();
|
|
||||||
for(p=knownfmt; p->c; p++)
|
|
||||||
if(p->c == c){
|
|
||||||
__fmtinstall(p->c, p->fmt);
|
|
||||||
__fmtunlock();
|
|
||||||
return p->fmt;
|
|
||||||
}
|
|
||||||
__fmtunlock();
|
|
||||||
|
|
||||||
return __badfmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
__fmtdispatch(Fmt *f, void *fmt, int isrunes)
|
|
||||||
{
|
|
||||||
Rune rune, r;
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
f->flags = 0;
|
|
||||||
f->width = f->prec = 0;
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
if(isrunes){
|
|
||||||
r = *(Rune*)fmt;
|
|
||||||
fmt = (Rune*)fmt + 1;
|
|
||||||
}else{
|
|
||||||
fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
|
|
||||||
r = rune;
|
|
||||||
}
|
|
||||||
f->r = r;
|
|
||||||
switch(r){
|
|
||||||
case '\0':
|
|
||||||
return nil;
|
|
||||||
case '.':
|
|
||||||
f->flags |= FmtWidth|FmtPrec;
|
|
||||||
continue;
|
|
||||||
case '0':
|
|
||||||
if(!(f->flags & FmtWidth)){
|
|
||||||
f->flags |= FmtZero;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* fall through */
|
|
||||||
case '1': case '2': case '3': case '4':
|
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
|
||||||
i = 0;
|
|
||||||
while(r >= '0' && r <= '9'){
|
|
||||||
i = i * 10 + r - '0';
|
|
||||||
if(isrunes){
|
|
||||||
r = *(Rune*)fmt;
|
|
||||||
fmt = (Rune*)fmt + 1;
|
|
||||||
}else{
|
|
||||||
r = *(char*)fmt;
|
|
||||||
fmt = (char*)fmt + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(isrunes)
|
|
||||||
fmt = (Rune*)fmt - 1;
|
|
||||||
else
|
|
||||||
fmt = (char*)fmt - 1;
|
|
||||||
numflag:
|
|
||||||
if(f->flags & FmtWidth){
|
|
||||||
f->flags |= FmtPrec;
|
|
||||||
f->prec = i;
|
|
||||||
}else{
|
|
||||||
f->flags |= FmtWidth;
|
|
||||||
f->width = i;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
case '*':
|
|
||||||
i = va_arg(f->args, int);
|
|
||||||
if(i < 0){
|
|
||||||
/*
|
|
||||||
* negative precision =>
|
|
||||||
* ignore the precision.
|
|
||||||
*/
|
|
||||||
if(f->flags & FmtPrec){
|
|
||||||
f->flags &= ~FmtPrec;
|
|
||||||
f->prec = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
i = -i;
|
|
||||||
f->flags |= FmtLeft;
|
|
||||||
}
|
|
||||||
goto numflag;
|
|
||||||
}
|
|
||||||
n = (*fmtfmt(r))(f);
|
|
||||||
if(n < 0)
|
|
||||||
return nil;
|
|
||||||
if(n == 0)
|
|
||||||
return fmt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* dofmt -- format to a buffer
|
|
||||||
* the number of characters formatted is returned,
|
|
||||||
* or -1 if there was an error.
|
|
||||||
* if the buffer is ever filled, flush is called.
|
|
||||||
* it should reset the buffer and return whether formatting should continue.
|
|
||||||
*/
|
|
||||||
#define uchar _fmtuchar
|
|
||||||
#define ushort _fmtushort
|
|
||||||
#define uint _fmtuint
|
|
||||||
#define ulong _fmtulong
|
|
||||||
#define vlong _fmtvlong
|
|
||||||
#define uvlong _fmtuvlong
|
|
||||||
|
|
||||||
#define USED(x) if(x);else
|
|
||||||
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
typedef unsigned short ushort;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef unsigned long ulong;
|
|
||||||
|
|
||||||
#ifndef NOVLONGS
|
|
||||||
typedef unsigned long long uvlong;
|
|
||||||
typedef long long vlong;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define nil 0 /* cannot be ((void*)0) because used for function pointers */
|
|
||||||
|
|
||||||
typedef int (*Fmts)(Fmt*);
|
|
||||||
|
|
||||||
typedef struct Quoteinfo Quoteinfo;
|
|
||||||
struct Quoteinfo
|
|
||||||
{
|
|
||||||
int quoted; /* if set, string must be quoted */
|
|
||||||
int nrunesin; /* number of input runes that can be accepted */
|
|
||||||
int nbytesin; /* number of input bytes that can be accepted */
|
|
||||||
int nrunesout; /* number of runes that will be generated */
|
|
||||||
int nbytesout; /* number of bytes that will be generated */
|
|
||||||
};
|
|
||||||
|
|
||||||
void *__fmtflush(Fmt*, void*, int);
|
|
||||||
void *__fmtdispatch(Fmt*, void*, int);
|
|
||||||
int __floatfmt(Fmt*, double);
|
|
||||||
int __fmtpad(Fmt*, int);
|
|
||||||
int __rfmtpad(Fmt*, int);
|
|
||||||
int __fmtFdFlush(Fmt*);
|
|
||||||
|
|
||||||
int __efgfmt(Fmt*);
|
|
||||||
int __charfmt(Fmt*);
|
|
||||||
int __runefmt(Fmt*);
|
|
||||||
int __runesfmt(Fmt*);
|
|
||||||
int __countfmt(Fmt*);
|
|
||||||
int __flagfmt(Fmt*);
|
|
||||||
int __percentfmt(Fmt*);
|
|
||||||
int __ifmt(Fmt*);
|
|
||||||
int __strfmt(Fmt*);
|
|
||||||
int __badfmt(Fmt*);
|
|
||||||
int __fmtcpy(Fmt*, const void*, int, int);
|
|
||||||
int __fmtrcpy(Fmt*, const void*, int n);
|
|
||||||
int __errfmt(Fmt *f);
|
|
||||||
|
|
||||||
double __fmtpow10(int);
|
|
||||||
|
|
||||||
void __fmtlock(void);
|
|
||||||
void __fmtunlock(void);
|
|
||||||
|
|
||||||
#define FMTCHAR(f, t, s, c)\
|
|
||||||
do{\
|
|
||||||
if(t + 1 > (char*)s){\
|
|
||||||
t = __fmtflush(f, t, 1);\
|
|
||||||
if(t != nil)\
|
|
||||||
s = f->stop;\
|
|
||||||
else\
|
|
||||||
return -1;\
|
|
||||||
}\
|
|
||||||
*t++ = c;\
|
|
||||||
}while(0)
|
|
||||||
|
|
||||||
#define FMTRCHAR(f, t, s, c)\
|
|
||||||
do{\
|
|
||||||
if(t + 1 > (Rune*)s){\
|
|
||||||
t = __fmtflush(f, t, sizeof(Rune));\
|
|
||||||
if(t != nil)\
|
|
||||||
s = f->stop;\
|
|
||||||
else\
|
|
||||||
return -1;\
|
|
||||||
}\
|
|
||||||
*t++ = c;\
|
|
||||||
}while(0)
|
|
||||||
|
|
||||||
#define FMTRUNE(f, t, s, r)\
|
|
||||||
do{\
|
|
||||||
Rune _rune;\
|
|
||||||
int _runelen;\
|
|
||||||
if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
|
|
||||||
t = __fmtflush(f, t, _runelen);\
|
|
||||||
if(t != nil)\
|
|
||||||
s = f->stop;\
|
|
||||||
else\
|
|
||||||
return -1;\
|
|
||||||
}\
|
|
||||||
if(r < Runeself)\
|
|
||||||
*t++ = r;\
|
|
||||||
else{\
|
|
||||||
_rune = r;\
|
|
||||||
t += runetochar(t, &_rune);\
|
|
||||||
}\
|
|
||||||
}while(0)
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* public routine for final flush of a formatting buffer
|
|
||||||
* to a file descriptor; returns total char count.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
fmtfdflush(Fmt *f)
|
|
||||||
{
|
|
||||||
if(__fmtFdFlush(f) <= 0)
|
|
||||||
return -1;
|
|
||||||
return f->nfmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize an output buffer for buffered printing
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
fmtfdinit(Fmt *f, int fd, char *buf, int size)
|
|
||||||
{
|
|
||||||
f->runes = 0;
|
|
||||||
f->start = buf;
|
|
||||||
f->to = buf;
|
|
||||||
f->stop = buf + size;
|
|
||||||
f->flush = __fmtFdFlush;
|
|
||||||
f->farg = (void*)fd;
|
|
||||||
f->nfmt = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* generic routine for flushing a formatting buffer
|
|
||||||
* to a file descriptor
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
__fmtFdFlush(Fmt *f)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = (char*)f->to - (char*)f->start;
|
|
||||||
if(n && write((int)f->farg, f->start, n) != n)
|
|
||||||
return 0;
|
|
||||||
f->to = f->start;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
__fmtlock(void)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__fmtunlock(void)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* format a string into the output buffer
|
|
||||||
* designed for formats which themselves call fmt,
|
|
||||||
* but ignore any width flags
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
fmtprint(Fmt *f, char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list va;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
f->flags = 0;
|
|
||||||
f->width = 0;
|
|
||||||
f->prec = 0;
|
|
||||||
va = f->args;
|
|
||||||
va_start(f->args, fmt);
|
|
||||||
n = dofmt(f, fmt);
|
|
||||||
va_end(f->args);
|
|
||||||
f->flags = 0;
|
|
||||||
f->width = 0;
|
|
||||||
f->prec = 0;
|
|
||||||
f->args = va;
|
|
||||||
if(n >= 0)
|
|
||||||
return 0;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,262 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
|
|
||||||
* How many runes? How much of the input will be consumed?
|
|
||||||
* The parameter q is filled in by __quotesetup.
|
|
||||||
* The string may be UTF or Runes (s or r).
|
|
||||||
* Return count does not include NUL.
|
|
||||||
* Terminate the scan at the first of:
|
|
||||||
* NUL in input
|
|
||||||
* count exceeded in input
|
|
||||||
* count exceeded on output
|
|
||||||
* *ninp is set to number of input bytes accepted.
|
|
||||||
* nin may be <0 initially, to avoid checking input by count.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
|
|
||||||
{
|
|
||||||
int w;
|
|
||||||
Rune c;
|
|
||||||
|
|
||||||
q->quoted = 0;
|
|
||||||
q->nbytesout = 0;
|
|
||||||
q->nrunesout = 0;
|
|
||||||
q->nbytesin = 0;
|
|
||||||
q->nrunesin = 0;
|
|
||||||
if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
|
|
||||||
if(nout < 2)
|
|
||||||
return;
|
|
||||||
q->quoted = 1;
|
|
||||||
q->nbytesout = 2;
|
|
||||||
q->nrunesout = 2;
|
|
||||||
}
|
|
||||||
for(; nin!=0; nin-=w){
|
|
||||||
if(s)
|
|
||||||
w = chartorune(&c, s);
|
|
||||||
else{
|
|
||||||
c = *r;
|
|
||||||
w = runelen(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c == '\0')
|
|
||||||
break;
|
|
||||||
if(runesout){
|
|
||||||
if(q->nrunesout+1 > nout)
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
if(q->nbytesout+w > nout)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
|
|
||||||
if(!q->quoted){
|
|
||||||
if(runesout){
|
|
||||||
if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
q->nrunesout += 2; /* include quotes */
|
|
||||||
q->nbytesout += 2; /* include quotes */
|
|
||||||
q->quoted = 1;
|
|
||||||
}
|
|
||||||
if(c == '\'') {
|
|
||||||
if(runesout){
|
|
||||||
if(1+q->nrunesout+1 > nout) /* no room for quotes */
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
if(1+q->nbytesout+w > nout) /* no room for quotes */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
q->nbytesout++;
|
|
||||||
q->nrunesout++; /* quotes reproduce as two characters */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* advance input */
|
|
||||||
if(s)
|
|
||||||
s += w;
|
|
||||||
else
|
|
||||||
r++;
|
|
||||||
q->nbytesin += w;
|
|
||||||
q->nrunesin++;
|
|
||||||
|
|
||||||
/* advance output */
|
|
||||||
q->nbytesout += w;
|
|
||||||
q->nrunesout++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
|
|
||||||
{
|
|
||||||
Rune r, *rm, *rme;
|
|
||||||
char *t, *s, *m, *me;
|
|
||||||
Rune *rt, *rs;
|
|
||||||
ulong fl;
|
|
||||||
int nc, w;
|
|
||||||
|
|
||||||
m = sin;
|
|
||||||
me = m + q->nbytesin;
|
|
||||||
rm = rin;
|
|
||||||
rme = rm + q->nrunesin;
|
|
||||||
|
|
||||||
w = f->width;
|
|
||||||
fl = f->flags;
|
|
||||||
if(f->runes){
|
|
||||||
if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
|
|
||||||
return -1;
|
|
||||||
}else{
|
|
||||||
if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
t = (char*)f->to;
|
|
||||||
s = (char*)f->stop;
|
|
||||||
rt = (Rune*)f->to;
|
|
||||||
rs = (Rune*)f->stop;
|
|
||||||
if(f->runes)
|
|
||||||
FMTRCHAR(f, rt, rs, '\'');
|
|
||||||
else
|
|
||||||
FMTRUNE(f, t, s, '\'');
|
|
||||||
for(nc = q->nrunesin; nc > 0; nc--){
|
|
||||||
if(sin){
|
|
||||||
r = *(uchar*)m;
|
|
||||||
if(r < Runeself)
|
|
||||||
m++;
|
|
||||||
else if((me - m) >= UTFmax || fullrune(m, me-m))
|
|
||||||
m += chartorune(&r, m);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
if(rm >= rme)
|
|
||||||
break;
|
|
||||||
r = *(uchar*)rm++;
|
|
||||||
}
|
|
||||||
if(f->runes){
|
|
||||||
FMTRCHAR(f, rt, rs, r);
|
|
||||||
if(r == '\'')
|
|
||||||
FMTRCHAR(f, rt, rs, r);
|
|
||||||
}else{
|
|
||||||
FMTRUNE(f, t, s, r);
|
|
||||||
if(r == '\'')
|
|
||||||
FMTRUNE(f, t, s, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(f->runes){
|
|
||||||
FMTRCHAR(f, rt, rs, '\'');
|
|
||||||
USED(rs);
|
|
||||||
f->nfmt += rt - (Rune *)f->to;
|
|
||||||
f->to = rt;
|
|
||||||
if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
|
|
||||||
return -1;
|
|
||||||
}else{
|
|
||||||
FMTRUNE(f, t, s, '\'');
|
|
||||||
USED(s);
|
|
||||||
f->nfmt += t - (char *)f->to;
|
|
||||||
f->to = t;
|
|
||||||
if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__quotestrfmt(int runesin, Fmt *f)
|
|
||||||
{
|
|
||||||
int outlen;
|
|
||||||
Rune *r;
|
|
||||||
char *s;
|
|
||||||
Quoteinfo q;
|
|
||||||
|
|
||||||
f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
|
|
||||||
if(runesin){
|
|
||||||
r = va_arg(f->args, Rune *);
|
|
||||||
s = nil;
|
|
||||||
}else{
|
|
||||||
s = va_arg(f->args, char *);
|
|
||||||
r = nil;
|
|
||||||
}
|
|
||||||
if(!s && !r)
|
|
||||||
return __fmtcpy(f, (void*)"<nil>", 5, 5);
|
|
||||||
|
|
||||||
if(f->flush)
|
|
||||||
outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
|
|
||||||
else if(f->runes)
|
|
||||||
outlen = (Rune*)f->stop - (Rune*)f->to;
|
|
||||||
else
|
|
||||||
outlen = (char*)f->stop - (char*)f->to;
|
|
||||||
|
|
||||||
__quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
|
|
||||||
//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
|
|
||||||
|
|
||||||
if(runesin){
|
|
||||||
if(!q.quoted)
|
|
||||||
return __fmtrcpy(f, r, q.nrunesin);
|
|
||||||
return qstrfmt(nil, r, &q, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!q.quoted)
|
|
||||||
return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
|
|
||||||
return qstrfmt(s, nil, &q, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
quotestrfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
return __quotestrfmt(0, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
quoterunestrfmt(Fmt *f)
|
|
||||||
{
|
|
||||||
return __quotestrfmt(1, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
quotefmtinstall(void)
|
|
||||||
{
|
|
||||||
fmtinstall('q', quotestrfmt);
|
|
||||||
fmtinstall('Q', quoterunestrfmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__needsquotes(char *s, int *quotelenp)
|
|
||||||
{
|
|
||||||
Quoteinfo q;
|
|
||||||
|
|
||||||
__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
|
|
||||||
*quotelenp = q.nbytesout;
|
|
||||||
|
|
||||||
return q.quoted;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__runeneedsquotes(Rune *r, int *quotelenp)
|
|
||||||
{
|
|
||||||
Quoteinfo q;
|
|
||||||
|
|
||||||
__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
|
|
||||||
*quotelenp = q.nrunesout;
|
|
||||||
|
|
||||||
return q.quoted;
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
fmtrune(Fmt *f, int r)
|
|
||||||
{
|
|
||||||
Rune *rt;
|
|
||||||
char *t;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if(f->runes){
|
|
||||||
rt = (Rune*)f->to;
|
|
||||||
FMTRCHAR(f, rt, f->stop, r);
|
|
||||||
f->to = rt;
|
|
||||||
n = 1;
|
|
||||||
}else{
|
|
||||||
t = (char*)f->to;
|
|
||||||
FMTRUNE(f, t, f->stop, r);
|
|
||||||
n = t - (char*)f->to;
|
|
||||||
f->to = t;
|
|
||||||
}
|
|
||||||
f->nfmt += n;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
static int
|
|
||||||
fmtStrFlush(Fmt *f)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = (int)f->farg;
|
|
||||||
n += 256;
|
|
||||||
f->farg = (void*)n;
|
|
||||||
s = (char*)f->start;
|
|
||||||
f->start = realloc(s, n);
|
|
||||||
if(f->start == nil){
|
|
||||||
f->start = s;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
f->to = (char*)f->start + ((char*)f->to - s);
|
|
||||||
f->stop = (char*)f->start + n - 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fmtstrinit(Fmt *f)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
f->runes = 0;
|
|
||||||
n = 32;
|
|
||||||
f->start = malloc(n);
|
|
||||||
if(f->start == nil)
|
|
||||||
return -1;
|
|
||||||
f->to = f->start;
|
|
||||||
f->stop = (char*)f->start + n - 1;
|
|
||||||
f->flush = fmtStrFlush;
|
|
||||||
f->farg = (void*)n;
|
|
||||||
f->nfmt = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
fmtstrflush(Fmt *f)
|
|
||||||
{
|
|
||||||
*(char*)f->to = '\0';
|
|
||||||
f->to = f->start;
|
|
||||||
return (char*)f->start;
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* format a string into the output buffer
|
|
||||||
* designed for formats which themselves call fmt,
|
|
||||||
* but ignore any width flags
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
fmtvprint(Fmt *f, char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
va_list va;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
f->flags = 0;
|
|
||||||
f->width = 0;
|
|
||||||
f->prec = 0;
|
|
||||||
va = f->args;
|
|
||||||
f->args = args;
|
|
||||||
n = dofmt(f, fmt);
|
|
||||||
f->flags = 0;
|
|
||||||
f->width = 0;
|
|
||||||
f->prec = 0;
|
|
||||||
f->args = va;
|
|
||||||
if(n >= 0)
|
|
||||||
return 0;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
fprint(int fd, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
n = vfprint(fd, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
PLAN9=../..
|
|
||||||
<$PLAN9/src/mkhdr
|
|
||||||
|
|
||||||
LIB=libfmt.a
|
|
||||||
|
|
||||||
NUM=\
|
|
||||||
charstod.$O\
|
|
||||||
pow10.$O\
|
|
||||||
|
|
||||||
# Could add errfmt, but we want to pick it up from lib9 instead.
|
|
||||||
OFILES=\
|
|
||||||
dofmt.$O\
|
|
||||||
errfmt.$O\
|
|
||||||
fltfmt.$O\
|
|
||||||
fmt.$O\
|
|
||||||
fmtfd.$O\
|
|
||||||
fmtfdflush.$O\
|
|
||||||
fmtlock.$O\
|
|
||||||
fmtprint.$O\
|
|
||||||
fmtquote.$O\
|
|
||||||
fmtrune.$O\
|
|
||||||
fmtstr.$O\
|
|
||||||
fmtvprint.$O\
|
|
||||||
fprint.$O\
|
|
||||||
nan64.$O\
|
|
||||||
print.$O\
|
|
||||||
runefmtstr.$O\
|
|
||||||
runeseprint.$O\
|
|
||||||
runesmprint.$O\
|
|
||||||
runesnprint.$O\
|
|
||||||
runesprint.$O\
|
|
||||||
runevseprint.$O\
|
|
||||||
runevsmprint.$O\
|
|
||||||
runevsnprint.$O\
|
|
||||||
seprint.$O\
|
|
||||||
smprint.$O\
|
|
||||||
snprint.$O\
|
|
||||||
sprint.$O\
|
|
||||||
strtod.$O\
|
|
||||||
vfprint.$O\
|
|
||||||
vseprint.$O\
|
|
||||||
vsmprint.$O\
|
|
||||||
vsnprint.$O\
|
|
||||||
$NUM\
|
|
||||||
|
|
||||||
HFILES=\
|
|
||||||
fmtdef.h\
|
|
||||||
$PLAN9/include/fmt.h\
|
|
||||||
|
|
||||||
<$PLAN9/src/mksyslib
|
|
||||||
|
|
||||||
$NAN.$O: nan.h
|
|
||||||
strtod.$O: nan.h
|
|
||||||
|
|
||||||
test: $LIB test.$O
|
|
||||||
$CC -o test test.$O $LIB -L$PLAN9/lib -lutf
|
|
||||||
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
extern double __NaN(void);
|
|
||||||
extern double __Inf(int);
|
|
||||||
extern int __isNaN(double);
|
|
||||||
extern int __isInf(double, int);
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* 64-bit IEEE not-a-number routines.
|
|
||||||
* This is big/little-endian portable assuming that
|
|
||||||
* the 64-bit doubles and 64-bit integers have the
|
|
||||||
* same byte ordering.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "nan.h"
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#define _NEEDLL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned long long uvlong;
|
|
||||||
typedef unsigned long ulong;
|
|
||||||
|
|
||||||
#ifdef _NEEDLL
|
|
||||||
static uvlong uvnan = 0x7FF0000000000001LL;
|
|
||||||
static uvlong uvinf = 0x7FF0000000000000LL;
|
|
||||||
static uvlong uvneginf = 0xFFF0000000000000LL;
|
|
||||||
#else
|
|
||||||
static uvlong uvnan = 0x7FF0000000000001;
|
|
||||||
static uvlong uvinf = 0x7FF0000000000000;
|
|
||||||
static uvlong uvneginf = 0xFFF0000000000000;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
double
|
|
||||||
__NaN(void)
|
|
||||||
{
|
|
||||||
uvlong *p;
|
|
||||||
|
|
||||||
/* gcc complains about "return *(double*)&uvnan;" */
|
|
||||||
p = &uvnan;
|
|
||||||
return *(double*)p;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__isNaN(double d)
|
|
||||||
{
|
|
||||||
uvlong x;
|
|
||||||
double *p;
|
|
||||||
|
|
||||||
p = &d;
|
|
||||||
x = *(uvlong*)p;
|
|
||||||
return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
__Inf(int sign)
|
|
||||||
{
|
|
||||||
uvlong *p;
|
|
||||||
|
|
||||||
if(sign < 0)
|
|
||||||
p = &uvinf;
|
|
||||||
else
|
|
||||||
p = &uvneginf;
|
|
||||||
return *(double*)p;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__isInf(double d, int sign)
|
|
||||||
{
|
|
||||||
uvlong x;
|
|
||||||
double *p;
|
|
||||||
|
|
||||||
p = &d;
|
|
||||||
x = *(uvlong*)p;
|
|
||||||
if(sign == 0)
|
|
||||||
return x==uvinf || x==uvneginf;
|
|
||||||
else if(sign > 0)
|
|
||||||
return x==uvinf;
|
|
||||||
else
|
|
||||||
return x==uvneginf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this table might overflow 127-bit exponent representations.
|
|
||||||
* in that case, truncate it after 1.0e38.
|
|
||||||
* it is important to get all one can from this
|
|
||||||
* routine since it is used in atof to scale numbers.
|
|
||||||
* the presumption is that C converts fp numbers better
|
|
||||||
* than multipication of lower powers of 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static
|
|
||||||
double tab[] =
|
|
||||||
{
|
|
||||||
1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
|
|
||||||
1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
|
|
||||||
1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
|
|
||||||
1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
|
|
||||||
1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
|
|
||||||
1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
|
|
||||||
1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
|
|
||||||
};
|
|
||||||
|
|
||||||
double
|
|
||||||
__fmtpow10(int n)
|
|
||||||
{
|
|
||||||
int m;
|
|
||||||
|
|
||||||
if(n < 0) {
|
|
||||||
n = -n;
|
|
||||||
if(n < (int)(sizeof(tab)/sizeof(tab[0])))
|
|
||||||
return 1/tab[n];
|
|
||||||
m = n/2;
|
|
||||||
return __fmtpow10(-m) * __fmtpow10(m-n);
|
|
||||||
}
|
|
||||||
if(n < (int)(sizeof(tab)/sizeof(tab[0])))
|
|
||||||
return tab[n];
|
|
||||||
m = n/2;
|
|
||||||
return __fmtpow10(m) * __fmtpow10(n-m);
|
|
||||||
}
|
|
||||||
@ -1,469 +0,0 @@
|
|||||||
.TH PRINT 3
|
|
||||||
.de EX
|
|
||||||
.nf
|
|
||||||
.ft B
|
|
||||||
..
|
|
||||||
.de EE
|
|
||||||
.fi
|
|
||||||
.ft R
|
|
||||||
..
|
|
||||||
.SH NAME
|
|
||||||
print, fprint, sprint, snprint, seprint, smprint, vfprint, vsnprint, vseprint, vsmprint \- print formatted output
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B #include <utf.h>
|
|
||||||
.PP
|
|
||||||
.B #include <fmt.h>
|
|
||||||
.PP
|
|
||||||
.ta \w'\fLchar* 'u
|
|
||||||
.B
|
|
||||||
int print(char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int fprint(int fd, char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int sprint(char *s, char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int snprint(char *s, int len, char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
char* seprint(char *s, char *e, char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
char* smprint(char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int runesprint(Rune *s, char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int runesnprint(Rune *s, int len, char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
Rune* runeseprint(Rune *s, Rune *e, char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
Rune* runesmprint(char *format, ...)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int vfprint(int fd, char *format, va_list v)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int vsnprint(char *s, int len, char *format, va_list v)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
char* vseprint(char *s, char *e, char *format, va_list v)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
char* vsmprint(char *format, va_list v)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
int runevsnprint(Rune *s, int len, char *format, va_list v)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
Rune* runevseprint(Rune *s, Rune *e, char *format, va_list v)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
Rune* runevsmprint(Rune *format, va_list v)
|
|
||||||
.PP
|
|
||||||
.B
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.I Print
|
|
||||||
writes text to the standard output.
|
|
||||||
.I Fprint
|
|
||||||
writes to the named output
|
|
||||||
file descriptor.
|
|
||||||
.I Sprint
|
|
||||||
places text
|
|
||||||
followed by the NUL character
|
|
||||||
.RB ( \e0 )
|
|
||||||
in consecutive bytes starting at
|
|
||||||
.IR s ;
|
|
||||||
it is the user's responsibility to ensure that
|
|
||||||
enough storage is available.
|
|
||||||
Each function returns the number of bytes
|
|
||||||
transmitted (not including the NUL
|
|
||||||
in the case of
|
|
||||||
.IR sprint ),
|
|
||||||
or
|
|
||||||
a negative value if an output error was encountered.
|
|
||||||
.PP
|
|
||||||
.I Snprint
|
|
||||||
is like
|
|
||||||
.IR sprint ,
|
|
||||||
but will not place more than
|
|
||||||
.I len
|
|
||||||
bytes in
|
|
||||||
.IR s .
|
|
||||||
Its result is always NUL-terminated and holds the maximal
|
|
||||||
number of characters that can fit.
|
|
||||||
.I Seprint
|
|
||||||
is like
|
|
||||||
.IR snprint ,
|
|
||||||
except that the end is indicated by a pointer
|
|
||||||
.I e
|
|
||||||
rather than a count and the return value points to the terminating NUL of the
|
|
||||||
resulting string.
|
|
||||||
.I Smprint
|
|
||||||
is like
|
|
||||||
.IR sprint ,
|
|
||||||
except that it prints into and returns a string of the required length, which is
|
|
||||||
allocated by
|
|
||||||
.IR malloc (3).
|
|
||||||
.PP
|
|
||||||
The routines
|
|
||||||
.IR runesprint ,
|
|
||||||
.IR runesnprint ,
|
|
||||||
.IR runeseprint ,
|
|
||||||
and
|
|
||||||
.I runesmprint
|
|
||||||
are the same as
|
|
||||||
.IR sprint ,
|
|
||||||
.IR snprint ,
|
|
||||||
.IR seprint
|
|
||||||
and
|
|
||||||
.I smprint
|
|
||||||
except that their output is rune strings instead of byte strings.
|
|
||||||
.PP
|
|
||||||
Finally, the routines
|
|
||||||
.IR vfprint ,
|
|
||||||
.IR vsnprint ,
|
|
||||||
.IR vseprint ,
|
|
||||||
.IR vsmprint ,
|
|
||||||
.IR runevsnprint ,
|
|
||||||
.IR runevseprint ,
|
|
||||||
and
|
|
||||||
.I runevsmprint
|
|
||||||
are like their
|
|
||||||
.BR v-less
|
|
||||||
relatives except they take as arguments a
|
|
||||||
.B va_list
|
|
||||||
parameter, so they can be called within a variadic function.
|
|
||||||
The Example section shows a representative usage.
|
|
||||||
.PP
|
|
||||||
Each of these functions
|
|
||||||
converts, formats, and prints its
|
|
||||||
trailing arguments
|
|
||||||
under control of a
|
|
||||||
.IR format
|
|
||||||
string.
|
|
||||||
The
|
|
||||||
format
|
|
||||||
contains two types of objects:
|
|
||||||
plain characters, which are simply copied to the
|
|
||||||
output stream,
|
|
||||||
and conversion specifications,
|
|
||||||
each of which results in fetching of
|
|
||||||
zero or more
|
|
||||||
arguments.
|
|
||||||
The results are undefined if there are arguments of the
|
|
||||||
wrong type or too few
|
|
||||||
arguments for the format.
|
|
||||||
If the format is exhausted while
|
|
||||||
arguments remain, the excess
|
|
||||||
is ignored.
|
|
||||||
.PP
|
|
||||||
Each conversion specification has the following format:
|
|
||||||
.IP
|
|
||||||
.B "% [flags] verb
|
|
||||||
.PP
|
|
||||||
The verb is a single character and each flag is a single character or a
|
|
||||||
(decimal) numeric string.
|
|
||||||
Up to two numeric strings may be used;
|
|
||||||
the first is called
|
|
||||||
.IR width ,
|
|
||||||
the second
|
|
||||||
.IR precision .
|
|
||||||
A period can be used to separate them, and if the period is
|
|
||||||
present then
|
|
||||||
.I width
|
|
||||||
and
|
|
||||||
.I precision
|
|
||||||
are taken to be zero if missing, otherwise they are `omitted'.
|
|
||||||
Either or both of the numbers may be replaced with the character
|
|
||||||
.BR * ,
|
|
||||||
meaning that the actual number will be obtained from the argument list
|
|
||||||
as an integer.
|
|
||||||
The flags and numbers are arguments to
|
|
||||||
the
|
|
||||||
.I verb
|
|
||||||
described below.
|
|
||||||
.PP
|
|
||||||
The numeric verbs
|
|
||||||
.BR d ,
|
|
||||||
.BR i ,
|
|
||||||
.BR u ,
|
|
||||||
.BR o ,
|
|
||||||
.BR b ,
|
|
||||||
.BR x ,
|
|
||||||
and
|
|
||||||
.B X
|
|
||||||
format their arguments in decimal, decimal,
|
|
||||||
unsigned decimal, octal, binary, hexadecimal, and upper case hexadecimal.
|
|
||||||
Each interprets the flags
|
|
||||||
.BR 0 ,
|
|
||||||
.BR h ,
|
|
||||||
.BR hh ,
|
|
||||||
.BR l ,
|
|
||||||
.BR + ,
|
|
||||||
.BR - ,
|
|
||||||
.BR , ,
|
|
||||||
and
|
|
||||||
.B #
|
|
||||||
to mean pad with zeros,
|
|
||||||
short, byte, long, always print a sign, left justified, commas every three digits,
|
|
||||||
and alternate format.
|
|
||||||
Also, a space character in the flag
|
|
||||||
position is like
|
|
||||||
.BR + ,
|
|
||||||
but prints a space instead of a plus sign for non-negative values.
|
|
||||||
If neither
|
|
||||||
short nor long is specified,
|
|
||||||
then the argument is an
|
|
||||||
.BR int .
|
|
||||||
If an unsigned verb is specified,
|
|
||||||
then the argument is interpreted as a
|
|
||||||
positive number and no sign is output;
|
|
||||||
space and
|
|
||||||
.B +
|
|
||||||
flags are ignored for unsigned verbs.
|
|
||||||
If two
|
|
||||||
.B l
|
|
||||||
flags are given,
|
|
||||||
then the argument is interpreted as a
|
|
||||||
.B vlong
|
|
||||||
(usually an 8-byte, sometimes a 4-byte integer).
|
|
||||||
If
|
|
||||||
.I precision
|
|
||||||
is not omitted, the number is padded on the left with zeros
|
|
||||||
until at least
|
|
||||||
.I precision
|
|
||||||
digits appear.
|
|
||||||
If
|
|
||||||
.I precision
|
|
||||||
is explicitly 0, and the number is 0,
|
|
||||||
no digits are generated, and alternate formatting
|
|
||||||
does not apply.
|
|
||||||
Then, if alternate format is specified,
|
|
||||||
for
|
|
||||||
.B o
|
|
||||||
conversion, the number is preceded by a
|
|
||||||
.B 0
|
|
||||||
if it doesn't already begin with one.
|
|
||||||
For non-zero numbers and
|
|
||||||
.B x
|
|
||||||
conversion, the number is preceded by
|
|
||||||
.BR 0x ;
|
|
||||||
for
|
|
||||||
.B X
|
|
||||||
conversion, the number is preceded by
|
|
||||||
.BR 0X .
|
|
||||||
Finally, if
|
|
||||||
.I width
|
|
||||||
is not omitted, the number is padded on the left (or right, if
|
|
||||||
left justification is specified) with enough blanks to
|
|
||||||
make the field at least
|
|
||||||
.I width
|
|
||||||
characters long.
|
|
||||||
.PP
|
|
||||||
The floating point verbs
|
|
||||||
.BR f ,
|
|
||||||
.BR e ,
|
|
||||||
.BR E ,
|
|
||||||
.BR g ,
|
|
||||||
and
|
|
||||||
.B G
|
|
||||||
take a
|
|
||||||
.B double
|
|
||||||
argument.
|
|
||||||
Each interprets the flags
|
|
||||||
.BR 0 ,
|
|
||||||
.BR L
|
|
||||||
.BR + ,
|
|
||||||
.BR - ,
|
|
||||||
and
|
|
||||||
.B #
|
|
||||||
to mean pad with zeros,
|
|
||||||
long double argument,
|
|
||||||
always print a sign,
|
|
||||||
left justified,
|
|
||||||
and
|
|
||||||
alternate format.
|
|
||||||
.I Width
|
|
||||||
is the minimum field width and,
|
|
||||||
if the converted value takes up less than
|
|
||||||
.I width
|
|
||||||
characters, it is padded on the left (or right, if `left justified')
|
|
||||||
with spaces.
|
|
||||||
.I Precision
|
|
||||||
is the number of digits that are converted after the decimal place for
|
|
||||||
.BR e ,
|
|
||||||
.BR E ,
|
|
||||||
and
|
|
||||||
.B f
|
|
||||||
conversions,
|
|
||||||
and
|
|
||||||
.I precision
|
|
||||||
is the maximum number of significant digits for
|
|
||||||
.B g
|
|
||||||
and
|
|
||||||
.B G
|
|
||||||
conversions.
|
|
||||||
The
|
|
||||||
.B f
|
|
||||||
verb produces output of the form
|
|
||||||
.RB [ - ] digits [ .digits\fR].
|
|
||||||
.B E
|
|
||||||
conversion appends an exponent
|
|
||||||
.BR E [ - ] digits ,
|
|
||||||
and
|
|
||||||
.B e
|
|
||||||
conversion appends an exponent
|
|
||||||
.BR e [ - ] digits .
|
|
||||||
The
|
|
||||||
.B g
|
|
||||||
verb will output the argument in either
|
|
||||||
.B e
|
|
||||||
or
|
|
||||||
.B f
|
|
||||||
with the goal of producing the smallest output.
|
|
||||||
Also, trailing zeros are omitted from the fraction part of
|
|
||||||
the output, and a trailing decimal point appears only if it is followed
|
|
||||||
by a digit.
|
|
||||||
The
|
|
||||||
.B G
|
|
||||||
verb is similar, but uses
|
|
||||||
.B E
|
|
||||||
format instead of
|
|
||||||
.BR e .
|
|
||||||
When alternate format is specified, the result will always contain a decimal point,
|
|
||||||
and for
|
|
||||||
.B g
|
|
||||||
and
|
|
||||||
.B G
|
|
||||||
conversions, trailing zeros are not removed.
|
|
||||||
.PP
|
|
||||||
The
|
|
||||||
.B s
|
|
||||||
verb copies a string
|
|
||||||
(pointer to
|
|
||||||
.BR char )
|
|
||||||
to the output.
|
|
||||||
The number of characters copied
|
|
||||||
.RI ( n )
|
|
||||||
is the minimum
|
|
||||||
of the size of the string and
|
|
||||||
.IR precision .
|
|
||||||
These
|
|
||||||
.I n
|
|
||||||
characters are justified within a field of
|
|
||||||
.I width
|
|
||||||
characters as described above.
|
|
||||||
If a
|
|
||||||
.I precision
|
|
||||||
is given, it is safe for the string not to be nul-terminated
|
|
||||||
as long as it is at least
|
|
||||||
.I precision
|
|
||||||
characters (not bytes!) long.
|
|
||||||
The
|
|
||||||
.B S
|
|
||||||
verb is similar, but it interprets its pointer as an array
|
|
||||||
of runes (see
|
|
||||||
.IR utf (7));
|
|
||||||
the runes are converted to
|
|
||||||
.SM UTF
|
|
||||||
before output.
|
|
||||||
.PP
|
|
||||||
The
|
|
||||||
.B c
|
|
||||||
verb copies a single
|
|
||||||
.B char
|
|
||||||
(promoted to
|
|
||||||
.BR int )
|
|
||||||
justified within a field of
|
|
||||||
.I width
|
|
||||||
characters as described above.
|
|
||||||
The
|
|
||||||
.B C
|
|
||||||
verb is similar, but works on runes.
|
|
||||||
.PP
|
|
||||||
The
|
|
||||||
.B p
|
|
||||||
verb formats a pointer value.
|
|
||||||
At the moment, it is a synonym for
|
|
||||||
.BR x ,
|
|
||||||
but that will change if pointers and integers are different sizes.
|
|
||||||
.PP
|
|
||||||
The
|
|
||||||
.B r
|
|
||||||
verb takes no arguments; it copies the error string returned by a call to
|
|
||||||
.IR strerror (3)
|
|
||||||
with an argument of
|
|
||||||
.IR errno.
|
|
||||||
.PP
|
|
||||||
Custom verbs may be installed using
|
|
||||||
.IR fmtinstall (3).
|
|
||||||
.SH EXAMPLE
|
|
||||||
This function prints an error message with a variable
|
|
||||||
number of arguments and then quits.
|
|
||||||
.IP
|
|
||||||
.EX
|
|
||||||
.ta 6n +6n +6n
|
|
||||||
void fatal(char *msg, ...)
|
|
||||||
{
|
|
||||||
char buf[1024], *out;
|
|
||||||
va_list arg;
|
|
||||||
|
|
||||||
out = vseprint(buf, buf+sizeof buf, "Fatal error: ");
|
|
||||||
va_start(arg, msg);
|
|
||||||
out = vseprint(out, buf+sizeof buf, msg, arg);
|
|
||||||
va_end(arg);
|
|
||||||
write(2, buf, out-buf);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
.EE
|
|
||||||
.SH SEE ALSO
|
|
||||||
.IR fmtinstall (3),
|
|
||||||
.IR fprintf (3),
|
|
||||||
.IR utf (7)
|
|
||||||
.SH DIAGNOSTICS
|
|
||||||
Routines that write to a file descriptor or call
|
|
||||||
.IR malloc
|
|
||||||
set
|
|
||||||
.IR errstr .
|
|
||||||
.SH BUGS
|
|
||||||
The formatting is close to that specified for ANSI
|
|
||||||
.IR fprintf (3);
|
|
||||||
the main difference is that
|
|
||||||
.B b
|
|
||||||
and
|
|
||||||
.B r
|
|
||||||
are not in ANSI and some
|
|
||||||
.B C9X
|
|
||||||
verbs are missing.
|
|
||||||
Also, and distinctly not a bug,
|
|
||||||
.I print
|
|
||||||
and friends generate
|
|
||||||
.SM UTF
|
|
||||||
rather than
|
|
||||||
.SM ASCII.
|
|
||||||
.PP
|
|
||||||
There is no
|
|
||||||
.BR runeprint ,
|
|
||||||
.BR runefprint ,
|
|
||||||
etc. because runes are byte-order dependent and should not be written directly to a file; use the
|
|
||||||
UTF output of
|
|
||||||
.I print
|
|
||||||
or
|
|
||||||
.I fprint
|
|
||||||
instead.
|
|
||||||
Also,
|
|
||||||
.I sprint
|
|
||||||
is deprecated for safety reasons; use
|
|
||||||
.IR snprint ,
|
|
||||||
.IR seprint ,
|
|
||||||
or
|
|
||||||
.I smprint
|
|
||||||
instead.
|
|
||||||
Safety also precludes the existence of
|
|
||||||
.IR runesprint .
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
print(char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
n = vfprint(1, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
static int
|
|
||||||
runeFmtStrFlush(Fmt *f)
|
|
||||||
{
|
|
||||||
Rune *s;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = (int)f->farg;
|
|
||||||
n += 256;
|
|
||||||
f->farg = (void*)n;
|
|
||||||
s = (Rune*)f->start;
|
|
||||||
f->start = realloc(s, sizeof(Rune)*n);
|
|
||||||
if(f->start == nil){
|
|
||||||
f->start = s;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
f->to = (Rune*)f->start + ((Rune*)f->to - s);
|
|
||||||
f->stop = (Rune*)f->start + n - 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
runefmtstrinit(Fmt *f)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
f->runes = 1;
|
|
||||||
n = 32;
|
|
||||||
f->start = malloc(sizeof(Rune)*n);
|
|
||||||
if(f->start == nil)
|
|
||||||
return -1;
|
|
||||||
f->to = f->start;
|
|
||||||
f->stop = (Rune*)f->start + n - 1;
|
|
||||||
f->flush = runeFmtStrFlush;
|
|
||||||
f->farg = (void*)n;
|
|
||||||
f->nfmt = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runefmtstrflush(Fmt *f)
|
|
||||||
{
|
|
||||||
*(Rune*)f->to = '\0';
|
|
||||||
f->to = f->start;
|
|
||||||
return f->start;
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runeseprint(Rune *buf, Rune *e, char *fmt, ...)
|
|
||||||
{
|
|
||||||
Rune *p;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
p = runevseprint(buf, e, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runesmprint(char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
Rune *p;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
p = runevsmprint(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
runesnprint(Rune *buf, int len, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
n = runevsnprint(buf, len, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
runesprint(Rune *buf, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
n = runevsnprint(buf, 256, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
Fmt f;
|
|
||||||
|
|
||||||
if(e <= buf)
|
|
||||||
return nil;
|
|
||||||
f.runes = 1;
|
|
||||||
f.start = buf;
|
|
||||||
f.to = buf;
|
|
||||||
f.stop = e - 1;
|
|
||||||
f.flush = nil;
|
|
||||||
f.farg = nil;
|
|
||||||
f.nfmt = 0;
|
|
||||||
f.args = args;
|
|
||||||
dofmt(&f, fmt);
|
|
||||||
*(Rune*)f.to = '\0';
|
|
||||||
return (Rune*)f.to;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* print into an allocated string buffer
|
|
||||||
*/
|
|
||||||
Rune*
|
|
||||||
runevsmprint(char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
Fmt f;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if(runefmtstrinit(&f) < 0)
|
|
||||||
return nil;
|
|
||||||
f.args = args;
|
|
||||||
n = dofmt(&f, fmt);
|
|
||||||
if(n < 0)
|
|
||||||
return nil;
|
|
||||||
*(Rune*)f.to = '\0';
|
|
||||||
return (Rune*)f.start;
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
runevsnprint(Rune *buf, int len, char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
Fmt f;
|
|
||||||
|
|
||||||
if(len <= 0)
|
|
||||||
return -1;
|
|
||||||
f.runes = 1;
|
|
||||||
f.start = buf;
|
|
||||||
f.to = buf;
|
|
||||||
f.stop = buf + len - 1;
|
|
||||||
f.flush = nil;
|
|
||||||
f.farg = nil;
|
|
||||||
f.nfmt = 0;
|
|
||||||
f.args = args;
|
|
||||||
dofmt(&f, fmt);
|
|
||||||
*(Rune*)f.to = '\0';
|
|
||||||
return (Rune*)f.to - buf;
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
|
|
||||||
char*
|
|
||||||
seprint(char *buf, char *e, char *fmt, ...)
|
|
||||||
{
|
|
||||||
char *p;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
p = vseprint(buf, e, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
|
|
||||||
char*
|
|
||||||
smprint(char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
p = vsmprint(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
snprint(char *buf, int len, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
n = vsnprint(buf, len, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
sprint(char *buf, char *fmt, ...)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
n = vsnprint(buf, 65536, fmt, args); /* big number, but sprint is deprecated anyway */
|
|
||||||
va_end(args);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
@ -1,539 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "nan.h"
|
|
||||||
|
|
||||||
#ifndef nelem
|
|
||||||
#define nelem(x) (sizeof(x)/sizeof *(x))
|
|
||||||
#endif
|
|
||||||
#define nil ((void*)0)
|
|
||||||
#define ulong _fmtulong
|
|
||||||
typedef unsigned long ulong;
|
|
||||||
|
|
||||||
static ulong
|
|
||||||
umuldiv(ulong a, ulong b, ulong c)
|
|
||||||
{
|
|
||||||
double d;
|
|
||||||
|
|
||||||
d = ((double)a * (double)b) / (double)c;
|
|
||||||
if(d >= 4294967295.)
|
|
||||||
d = 4294967295.;
|
|
||||||
return (ulong)d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine will convert to arbitrary precision
|
|
||||||
* floating point entirely in multi-precision fixed.
|
|
||||||
* The answer is the closest floating point number to
|
|
||||||
* the given decimal number. Exactly half way are
|
|
||||||
* rounded ala ieee rules.
|
|
||||||
* Method is to scale input decimal between .500 and .999...
|
|
||||||
* with external power of 2, then binary search for the
|
|
||||||
* closest mantissa to this decimal number.
|
|
||||||
* Nmant is is the required precision. (53 for ieee dp)
|
|
||||||
* Nbits is the max number of bits/word. (must be <= 28)
|
|
||||||
* Prec is calculated - the number of words of fixed mantissa.
|
|
||||||
*/
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
Nbits = 28, /* bits safely represented in a ulong */
|
|
||||||
Nmant = 53, /* bits of precision required */
|
|
||||||
Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */
|
|
||||||
Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */
|
|
||||||
Ndig = 1500,
|
|
||||||
One = (ulong)(1<<Nbits),
|
|
||||||
Half = (ulong)(One>>1),
|
|
||||||
Maxe = 310,
|
|
||||||
|
|
||||||
Fsign = 1<<0, /* found - */
|
|
||||||
Fesign = 1<<1, /* found e- */
|
|
||||||
Fdpoint = 1<<2, /* found . */
|
|
||||||
|
|
||||||
S0 = 0, /* _ _S0 +S1 #S2 .S3 */
|
|
||||||
S1, /* _+ #S2 .S3 */
|
|
||||||
S2, /* _+# #S2 .S4 eS5 */
|
|
||||||
S3, /* _+. #S4 */
|
|
||||||
S4, /* _+#.# #S4 eS5 */
|
|
||||||
S5, /* _+#.#e +S6 #S7 */
|
|
||||||
S6, /* _+#.#e+ #S7 */
|
|
||||||
S7, /* _+#.#e+# #S7 */
|
|
||||||
};
|
|
||||||
|
|
||||||
static int xcmp(char*, char*);
|
|
||||||
static int fpcmp(char*, ulong*);
|
|
||||||
static void frnorm(ulong*);
|
|
||||||
static void divascii(char*, int*, int*, int*);
|
|
||||||
static void mulascii(char*, int*, int*, int*);
|
|
||||||
|
|
||||||
typedef struct Tab Tab;
|
|
||||||
struct Tab
|
|
||||||
{
|
|
||||||
int bp;
|
|
||||||
int siz;
|
|
||||||
char* cmp;
|
|
||||||
};
|
|
||||||
|
|
||||||
double
|
|
||||||
fmtstrtod(const char *as, char **aas)
|
|
||||||
{
|
|
||||||
int na, ex, dp, bp, c, i, flag, state;
|
|
||||||
ulong low[Prec], hig[Prec], mid[Prec];
|
|
||||||
double d;
|
|
||||||
char *s, a[Ndig];
|
|
||||||
|
|
||||||
flag = 0; /* Fsign, Fesign, Fdpoint */
|
|
||||||
na = 0; /* number of digits of a[] */
|
|
||||||
dp = 0; /* na of decimal point */
|
|
||||||
ex = 0; /* exonent */
|
|
||||||
|
|
||||||
state = S0;
|
|
||||||
for(s=(char*)as;; s++) {
|
|
||||||
c = *s;
|
|
||||||
if(c >= '0' && c <= '9') {
|
|
||||||
switch(state) {
|
|
||||||
case S0:
|
|
||||||
case S1:
|
|
||||||
case S2:
|
|
||||||
state = S2;
|
|
||||||
break;
|
|
||||||
case S3:
|
|
||||||
case S4:
|
|
||||||
state = S4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case S5:
|
|
||||||
case S6:
|
|
||||||
case S7:
|
|
||||||
state = S7;
|
|
||||||
ex = ex*10 + (c-'0');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(na == 0 && c == '0') {
|
|
||||||
dp--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(na < Ndig-50)
|
|
||||||
a[na++] = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch(c) {
|
|
||||||
case '\t':
|
|
||||||
case '\n':
|
|
||||||
case '\v':
|
|
||||||
case '\f':
|
|
||||||
case '\r':
|
|
||||||
case ' ':
|
|
||||||
if(state == S0)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
if(state == S0)
|
|
||||||
flag |= Fsign;
|
|
||||||
else
|
|
||||||
flag |= Fesign;
|
|
||||||
case '+':
|
|
||||||
if(state == S0)
|
|
||||||
state = S1;
|
|
||||||
else
|
|
||||||
if(state == S5)
|
|
||||||
state = S6;
|
|
||||||
else
|
|
||||||
break; /* syntax */
|
|
||||||
continue;
|
|
||||||
case '.':
|
|
||||||
flag |= Fdpoint;
|
|
||||||
dp = na;
|
|
||||||
if(state == S0 || state == S1) {
|
|
||||||
state = S3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(state == S2) {
|
|
||||||
state = S4;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
case 'E':
|
|
||||||
if(state == S2 || state == S4) {
|
|
||||||
state = S5;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clean up return char-pointer
|
|
||||||
*/
|
|
||||||
switch(state) {
|
|
||||||
case S0:
|
|
||||||
if(xcmp(s, "nan") == 0) {
|
|
||||||
if(aas != nil)
|
|
||||||
*aas = s+3;
|
|
||||||
goto retnan;
|
|
||||||
}
|
|
||||||
case S1:
|
|
||||||
if(xcmp(s, "infinity") == 0) {
|
|
||||||
if(aas != nil)
|
|
||||||
*aas = s+8;
|
|
||||||
goto retinf;
|
|
||||||
}
|
|
||||||
if(xcmp(s, "inf") == 0) {
|
|
||||||
if(aas != nil)
|
|
||||||
*aas = s+3;
|
|
||||||
goto retinf;
|
|
||||||
}
|
|
||||||
case S3:
|
|
||||||
if(aas != nil)
|
|
||||||
*aas = (char*)as;
|
|
||||||
goto ret0; /* no digits found */
|
|
||||||
case S6:
|
|
||||||
s--; /* back over +- */
|
|
||||||
case S5:
|
|
||||||
s--; /* back over e */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(aas != nil)
|
|
||||||
*aas = s;
|
|
||||||
|
|
||||||
if(flag & Fdpoint)
|
|
||||||
while(na > 0 && a[na-1] == '0')
|
|
||||||
na--;
|
|
||||||
if(na == 0)
|
|
||||||
goto ret0; /* zero */
|
|
||||||
a[na] = 0;
|
|
||||||
if(!(flag & Fdpoint))
|
|
||||||
dp = na;
|
|
||||||
if(flag & Fesign)
|
|
||||||
ex = -ex;
|
|
||||||
dp += ex;
|
|
||||||
if(dp < -Maxe){
|
|
||||||
errno = ERANGE;
|
|
||||||
goto ret0; /* underflow by exp */
|
|
||||||
} else
|
|
||||||
if(dp > +Maxe)
|
|
||||||
goto retinf; /* overflow by exp */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* normalize the decimal ascii number
|
|
||||||
* to range .[5-9][0-9]* e0
|
|
||||||
*/
|
|
||||||
bp = 0; /* binary exponent */
|
|
||||||
while(dp > 0)
|
|
||||||
divascii(a, &na, &dp, &bp);
|
|
||||||
while(dp < 0 || a[0] < '5')
|
|
||||||
mulascii(a, &na, &dp, &bp);
|
|
||||||
|
|
||||||
/* close approx by naive conversion */
|
|
||||||
mid[0] = 0;
|
|
||||||
mid[1] = 1;
|
|
||||||
for(i=0; c=a[i]; i++) {
|
|
||||||
mid[0] = mid[0]*10 + (c-'0');
|
|
||||||
mid[1] = mid[1]*10;
|
|
||||||
if(i >= 8)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
low[0] = umuldiv(mid[0], One, mid[1]);
|
|
||||||
hig[0] = umuldiv(mid[0]+1, One, mid[1]);
|
|
||||||
for(i=1; i<Prec; i++) {
|
|
||||||
low[i] = 0;
|
|
||||||
hig[i] = One-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* binary search for closest mantissa */
|
|
||||||
for(;;) {
|
|
||||||
/* mid = (hig + low) / 2 */
|
|
||||||
c = 0;
|
|
||||||
for(i=0; i<Prec; i++) {
|
|
||||||
mid[i] = hig[i] + low[i];
|
|
||||||
if(c)
|
|
||||||
mid[i] += One;
|
|
||||||
c = mid[i] & 1;
|
|
||||||
mid[i] >>= 1;
|
|
||||||
}
|
|
||||||
frnorm(mid);
|
|
||||||
|
|
||||||
/* compare */
|
|
||||||
c = fpcmp(a, mid);
|
|
||||||
if(c > 0) {
|
|
||||||
c = 1;
|
|
||||||
for(i=0; i<Prec; i++)
|
|
||||||
if(low[i] != mid[i]) {
|
|
||||||
c = 0;
|
|
||||||
low[i] = mid[i];
|
|
||||||
}
|
|
||||||
if(c)
|
|
||||||
break; /* between mid and hig */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(c < 0) {
|
|
||||||
for(i=0; i<Prec; i++)
|
|
||||||
hig[i] = mid[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* only hard part is if even/odd roundings wants to go up */
|
|
||||||
c = mid[Prec-1] & (Sigbit-1);
|
|
||||||
if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
|
|
||||||
mid[Prec-1] -= c;
|
|
||||||
break; /* exactly mid */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* normal rounding applies */
|
|
||||||
c = mid[Prec-1] & (Sigbit-1);
|
|
||||||
mid[Prec-1] -= c;
|
|
||||||
if(c >= Sigbit/2) {
|
|
||||||
mid[Prec-1] += Sigbit;
|
|
||||||
frnorm(mid);
|
|
||||||
}
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret0:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
retnan:
|
|
||||||
return __NaN();
|
|
||||||
|
|
||||||
retinf:
|
|
||||||
/*
|
|
||||||
* Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */
|
|
||||||
errno = ERANGE;
|
|
||||||
if(flag & Fsign)
|
|
||||||
return -HUGE_VAL;
|
|
||||||
return HUGE_VAL;
|
|
||||||
|
|
||||||
out:
|
|
||||||
d = 0;
|
|
||||||
for(i=0; i<Prec; i++)
|
|
||||||
d = d*One + mid[i];
|
|
||||||
if(flag & Fsign)
|
|
||||||
d = -d;
|
|
||||||
d = ldexp(d, bp - Prec*Nbits);
|
|
||||||
if(d == 0){ /* underflow */
|
|
||||||
errno = ERANGE;
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
frnorm(ulong *f)
|
|
||||||
{
|
|
||||||
int i, c;
|
|
||||||
|
|
||||||
c = 0;
|
|
||||||
for(i=Prec-1; i>0; i--) {
|
|
||||||
f[i] += c;
|
|
||||||
c = f[i] >> Nbits;
|
|
||||||
f[i] &= One-1;
|
|
||||||
}
|
|
||||||
f[0] += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
fpcmp(char *a, ulong* f)
|
|
||||||
{
|
|
||||||
ulong tf[Prec];
|
|
||||||
int i, d, c;
|
|
||||||
|
|
||||||
for(i=0; i<Prec; i++)
|
|
||||||
tf[i] = f[i];
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
/* tf *= 10 */
|
|
||||||
for(i=0; i<Prec; i++)
|
|
||||||
tf[i] = tf[i]*10;
|
|
||||||
frnorm(tf);
|
|
||||||
d = (tf[0] >> Nbits) + '0';
|
|
||||||
tf[0] &= One-1;
|
|
||||||
|
|
||||||
/* compare next digit */
|
|
||||||
c = *a;
|
|
||||||
if(c == 0) {
|
|
||||||
if('0' < d)
|
|
||||||
return -1;
|
|
||||||
if(tf[0] != 0)
|
|
||||||
goto cont;
|
|
||||||
for(i=1; i<Prec; i++)
|
|
||||||
if(tf[i] != 0)
|
|
||||||
goto cont;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(c > d)
|
|
||||||
return +1;
|
|
||||||
if(c < d)
|
|
||||||
return -1;
|
|
||||||
a++;
|
|
||||||
cont:;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
divby(char *a, int *na, int b)
|
|
||||||
{
|
|
||||||
int n, c;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
p = a;
|
|
||||||
n = 0;
|
|
||||||
while(n>>b == 0) {
|
|
||||||
c = *a++;
|
|
||||||
if(c == 0) {
|
|
||||||
while(n) {
|
|
||||||
c = n*10;
|
|
||||||
if(c>>b)
|
|
||||||
break;
|
|
||||||
n = c;
|
|
||||||
}
|
|
||||||
goto xx;
|
|
||||||
}
|
|
||||||
n = n*10 + c-'0';
|
|
||||||
(*na)--;
|
|
||||||
}
|
|
||||||
for(;;) {
|
|
||||||
c = n>>b;
|
|
||||||
n -= c<<b;
|
|
||||||
*p++ = c + '0';
|
|
||||||
c = *a++;
|
|
||||||
if(c == 0)
|
|
||||||
break;
|
|
||||||
n = n*10 + c-'0';
|
|
||||||
}
|
|
||||||
(*na)++;
|
|
||||||
xx:
|
|
||||||
while(n) {
|
|
||||||
n = n*10;
|
|
||||||
c = n>>b;
|
|
||||||
n -= c<<b;
|
|
||||||
*p++ = c + '0';
|
|
||||||
(*na)++;
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Tab tab1[] =
|
|
||||||
{
|
|
||||||
1, 0, "",
|
|
||||||
3, 1, "7",
|
|
||||||
6, 2, "63",
|
|
||||||
9, 3, "511",
|
|
||||||
13, 4, "8191",
|
|
||||||
16, 5, "65535",
|
|
||||||
19, 6, "524287",
|
|
||||||
23, 7, "8388607",
|
|
||||||
26, 8, "67108863",
|
|
||||||
27, 9, "134217727",
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
divascii(char *a, int *na, int *dp, int *bp)
|
|
||||||
{
|
|
||||||
int b, d;
|
|
||||||
Tab *t;
|
|
||||||
|
|
||||||
d = *dp;
|
|
||||||
if(d >= (int)(nelem(tab1)))
|
|
||||||
d = (int)(nelem(tab1))-1;
|
|
||||||
t = tab1 + d;
|
|
||||||
b = t->bp;
|
|
||||||
if(memcmp(a, t->cmp, t->siz) > 0)
|
|
||||||
d--;
|
|
||||||
*dp -= d;
|
|
||||||
*bp += b;
|
|
||||||
divby(a, na, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
mulby(char *a, char *p, char *q, int b)
|
|
||||||
{
|
|
||||||
int n, c;
|
|
||||||
|
|
||||||
n = 0;
|
|
||||||
*p = 0;
|
|
||||||
for(;;) {
|
|
||||||
q--;
|
|
||||||
if(q < a)
|
|
||||||
break;
|
|
||||||
c = *q - '0';
|
|
||||||
c = (c<<b) + n;
|
|
||||||
n = c/10;
|
|
||||||
c -= n*10;
|
|
||||||
p--;
|
|
||||||
*p = c + '0';
|
|
||||||
}
|
|
||||||
while(n) {
|
|
||||||
c = n;
|
|
||||||
n = c/10;
|
|
||||||
c -= n*10;
|
|
||||||
p--;
|
|
||||||
*p = c + '0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Tab tab2[] =
|
|
||||||
{
|
|
||||||
1, 1, "", /* dp = 0-0 */
|
|
||||||
3, 3, "125",
|
|
||||||
6, 5, "15625",
|
|
||||||
9, 7, "1953125",
|
|
||||||
13, 10, "1220703125",
|
|
||||||
16, 12, "152587890625",
|
|
||||||
19, 14, "19073486328125",
|
|
||||||
23, 17, "11920928955078125",
|
|
||||||
26, 19, "1490116119384765625",
|
|
||||||
27, 19, "7450580596923828125", /* dp 8-9 */
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
mulascii(char *a, int *na, int *dp, int *bp)
|
|
||||||
{
|
|
||||||
char *p;
|
|
||||||
int d, b;
|
|
||||||
Tab *t;
|
|
||||||
|
|
||||||
d = -*dp;
|
|
||||||
if(d >= (int)(nelem(tab2)))
|
|
||||||
d = (int)(nelem(tab2))-1;
|
|
||||||
t = tab2 + d;
|
|
||||||
b = t->bp;
|
|
||||||
if(memcmp(a, t->cmp, t->siz) < 0)
|
|
||||||
d--;
|
|
||||||
p = a + *na;
|
|
||||||
*bp -= b;
|
|
||||||
*dp += d;
|
|
||||||
*na += d;
|
|
||||||
mulby(a, p+d, p, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
xcmp(char *a, char *b)
|
|
||||||
{
|
|
||||||
int c1, c2;
|
|
||||||
|
|
||||||
while(c1 = *b++) {
|
|
||||||
c2 = *a++;
|
|
||||||
if(isupper(c2))
|
|
||||||
c2 = tolower(c2);
|
|
||||||
if(c1 != c2)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
extern double __NaN(void);
|
|
||||||
extern double __Inf(int);
|
|
||||||
extern double __isNaN(double);
|
|
||||||
extern double __isInf(double, int);
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <utf.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
quotefmtinstall();
|
|
||||||
print("hello world\n");
|
|
||||||
print("x: %x\n", 0x87654321);
|
|
||||||
print("u: %u\n", 0x87654321);
|
|
||||||
print("d: %d\n", 0x87654321);
|
|
||||||
print("s: %s\n", "hi there");
|
|
||||||
print("q: %q\n", "hi i'm here");
|
|
||||||
print("c: %c\n", '!');
|
|
||||||
print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
|
|
||||||
print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
|
|
||||||
print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
|
|
||||||
print("smiley: %C\n", (Rune)0x263a);
|
|
||||||
print("%g %.18\n", 2e25, 2e25);
|
|
||||||
print("%2.18g\n", 1.0);
|
|
||||||
print("%f\n", 3.1415927/4);
|
|
||||||
print("%d\n", 23);
|
|
||||||
print("%i\n", 23);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
vfprint(int fd, char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
Fmt f;
|
|
||||||
char buf[256];
|
|
||||||
int n;
|
|
||||||
|
|
||||||
fmtfdinit(&f, fd, buf, sizeof(buf));
|
|
||||||
f.args = args;
|
|
||||||
n = dofmt(&f, fmt);
|
|
||||||
if(n > 0 && __fmtFdFlush(&f) == 0)
|
|
||||||
return -1;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
char*
|
|
||||||
vseprint(char *buf, char *e, char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
Fmt f;
|
|
||||||
|
|
||||||
if(e <= buf)
|
|
||||||
return nil;
|
|
||||||
f.runes = 0;
|
|
||||||
f.start = buf;
|
|
||||||
f.to = buf;
|
|
||||||
f.stop = e - 1;
|
|
||||||
f.flush = 0;
|
|
||||||
f.farg = nil;
|
|
||||||
f.nfmt = 0;
|
|
||||||
f.args = args;
|
|
||||||
dofmt(&f, fmt);
|
|
||||||
*(char*)f.to = '\0';
|
|
||||||
return (char*)f.to;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* print into an allocated string buffer
|
|
||||||
*/
|
|
||||||
char*
|
|
||||||
vsmprint(char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
Fmt f;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if(fmtstrinit(&f) < 0)
|
|
||||||
return nil;
|
|
||||||
f.args = args;
|
|
||||||
n = dofmt(&f, fmt);
|
|
||||||
if(n < 0)
|
|
||||||
return nil;
|
|
||||||
*(char*)f.to = '\0';
|
|
||||||
return (char*)f.start;
|
|
||||||
}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "fmt.h"
|
|
||||||
#include "fmtdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
vsnprint(char *buf, int len, char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
Fmt f;
|
|
||||||
|
|
||||||
if(len <= 0)
|
|
||||||
return -1;
|
|
||||||
f.runes = 0;
|
|
||||||
f.start = buf;
|
|
||||||
f.to = buf;
|
|
||||||
f.stop = buf + len - 1;
|
|
||||||
f.flush = 0;
|
|
||||||
f.farg = nil;
|
|
||||||
f.nfmt = 0;
|
|
||||||
f.args = args;
|
|
||||||
dofmt(&f, fmt);
|
|
||||||
*(char*)f.to = '\0';
|
|
||||||
return (char*)f.to - buf;
|
|
||||||
}
|
|
||||||
@ -5,6 +5,7 @@
|
|||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <fcall.h>
|
#include <fcall.h>
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
|
#include <thread.h>
|
||||||
#include "fsimpl.h"
|
#include "fsimpl.h"
|
||||||
|
|
||||||
static int _fssend(Mux*, void*);
|
static int _fssend(Mux*, void*);
|
||||||
@ -270,7 +271,7 @@ _fsrecv(Mux *mux)
|
|||||||
Fsys *fs;
|
Fsys *fs;
|
||||||
|
|
||||||
fs = mux->aux;
|
fs = mux->aux;
|
||||||
n = readn(fs->fd, buf, 4);
|
n = threadreadn(fs->fd, buf, 4);
|
||||||
if(n != 4)
|
if(n != 4)
|
||||||
return nil;
|
return nil;
|
||||||
n = GBIT32(buf);
|
n = GBIT32(buf);
|
||||||
@ -280,12 +281,12 @@ _fsrecv(Mux *mux)
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
PBIT32(pkt, n);
|
PBIT32(pkt, n);
|
||||||
if(readn(fs->fd, pkt+4, n-4) != n-4){
|
if(threadreadn(fs->fd, pkt+4, n-4) != n-4){
|
||||||
free(pkt);
|
free(pkt);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
if(pkt[4] == Ropenfd){
|
if(pkt[4] == Ropenfd){
|
||||||
if((nfd=recvfd(fs->fd)) < 0){
|
if((nfd=threadrecvfd(fs->fd)) < 0){
|
||||||
fprint(2, "recv fd error: %r\n");
|
fprint(2, "recv fd error: %r\n");
|
||||||
free(pkt);
|
free(pkt);
|
||||||
return nil;
|
return nil;
|
||||||
|
|||||||
@ -12,7 +12,12 @@ fspread(Fid *fid, void *buf, long n, vlong offset)
|
|||||||
{
|
{
|
||||||
Fcall tx, rx;
|
Fcall tx, rx;
|
||||||
void *freep;
|
void *freep;
|
||||||
|
uint msize;
|
||||||
|
|
||||||
|
msize = fid->fs->msize - IOHDRSZ;
|
||||||
|
fprint(2, "n %d msize %d\n", n, msize);
|
||||||
|
if(n > msize)
|
||||||
|
n = msize;
|
||||||
tx.type = Tread;
|
tx.type = Tread;
|
||||||
tx.fid = fid->fid;
|
tx.fid = fid->fid;
|
||||||
if(offset == -1){
|
if(offset == -1){
|
||||||
|
|||||||
@ -7,8 +7,8 @@
|
|||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include "fsimpl.h"
|
#include "fsimpl.h"
|
||||||
|
|
||||||
long
|
static long
|
||||||
fspwrite(Fid *fid, void *buf, long n, vlong offset)
|
_fspwrite(Fid *fid, void *buf, long n, vlong offset)
|
||||||
{
|
{
|
||||||
Fcall tx, rx;
|
Fcall tx, rx;
|
||||||
void *freep;
|
void *freep;
|
||||||
@ -39,6 +39,31 @@ fspwrite(Fid *fid, void *buf, long n, vlong offset)
|
|||||||
return rx.count;
|
return rx.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
fspwrite(Fid *fid, void *buf, long n, vlong offset)
|
||||||
|
{
|
||||||
|
long tot, want, got;
|
||||||
|
uint msize;
|
||||||
|
|
||||||
|
msize = fid->fs->msize - IOHDRSZ;
|
||||||
|
tot = 0;
|
||||||
|
while(tot < n){
|
||||||
|
want = n - tot;
|
||||||
|
if(want > msize)
|
||||||
|
want = msize;
|
||||||
|
got = _fspwrite(fid, buf, want, offset);
|
||||||
|
if(got < 0){
|
||||||
|
if(tot == 0)
|
||||||
|
return got;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tot += got;
|
||||||
|
if(offset != -1)
|
||||||
|
offset += got;
|
||||||
|
}
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
|
||||||
long
|
long
|
||||||
fswrite(Fid *fid, void *buf, long n)
|
fswrite(Fid *fid, void *buf, long n)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,6 +5,7 @@ LIB=libplumb.a
|
|||||||
OFILES=\
|
OFILES=\
|
||||||
event.$O\
|
event.$O\
|
||||||
mesg.$O\
|
mesg.$O\
|
||||||
|
thread.$O\
|
||||||
|
|
||||||
HFILES=$PLAN9/include/plumb.h
|
HFILES=$PLAN9/include/plumb.h
|
||||||
|
|
||||||
|
|||||||
@ -65,9 +65,7 @@ chaninit(Channel *c, int elemsize, int elemcnt)
|
|||||||
{
|
{
|
||||||
if(elemcnt < 0 || elemsize <= 0 || c == nil)
|
if(elemcnt < 0 || elemsize <= 0 || c == nil)
|
||||||
return -1;
|
return -1;
|
||||||
c->f = 0;
|
memset(c, 0, sizeof *c);
|
||||||
c->n = 0;
|
|
||||||
c->freed = 0;
|
|
||||||
c->e = elemsize;
|
c->e = elemsize;
|
||||||
c->s = elemcnt;
|
c->s = elemcnt;
|
||||||
_threaddebug(DBGCHAN, "chaninit %p", c);
|
_threaddebug(DBGCHAN, "chaninit %p", c);
|
||||||
@ -104,13 +102,16 @@ alt(Alt *alts)
|
|||||||
* chanlock. Instead, we delay the note until we've dropped
|
* chanlock. Instead, we delay the note until we've dropped
|
||||||
* the lock.
|
* the lock.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* T might be nil here -- the scheduler sends on threadwaitchan
|
||||||
|
* directly (in non-blocking mode, of course!).
|
||||||
|
*/
|
||||||
t = _threadgetproc()->thread;
|
t = _threadgetproc()->thread;
|
||||||
if(t->moribund || _threadexitsallstatus)
|
if((t && t->moribund) || _threadexitsallstatus)
|
||||||
yield(); /* won't return */
|
yield(); /* won't return */
|
||||||
s = _procsplhi();
|
s = _procsplhi();
|
||||||
lock(&chanlock);
|
lock(&chanlock);
|
||||||
t->alt = alts;
|
|
||||||
t->chan = Chanalt;
|
|
||||||
|
|
||||||
/* test whether any channels can proceed */
|
/* test whether any channels can proceed */
|
||||||
n = 0;
|
n = 0;
|
||||||
@ -125,7 +126,6 @@ alt(Alt *alts)
|
|||||||
if(c==nil){
|
if(c==nil){
|
||||||
unlock(&chanlock);
|
unlock(&chanlock);
|
||||||
_procsplx(s);
|
_procsplx(s);
|
||||||
t->chan = Channone;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(canexec(xa))
|
if(canexec(xa))
|
||||||
@ -138,7 +138,6 @@ alt(Alt *alts)
|
|||||||
if(xa->op == CHANNOBLK){
|
if(xa->op == CHANNOBLK){
|
||||||
unlock(&chanlock);
|
unlock(&chanlock);
|
||||||
_procsplx(s);
|
_procsplx(s);
|
||||||
t->chan = Channone;
|
|
||||||
_threadnalt++;
|
_threadnalt++;
|
||||||
return xa - alts;
|
return xa - alts;
|
||||||
}
|
}
|
||||||
@ -159,6 +158,9 @@ _threadnalt++;
|
|||||||
* we need to be here.
|
* we need to be here.
|
||||||
*/
|
*/
|
||||||
Again:
|
Again:
|
||||||
|
t->alt = alts;
|
||||||
|
t->chan = Chanalt;
|
||||||
|
|
||||||
unlock(&chanlock);
|
unlock(&chanlock);
|
||||||
_procsplx(s);
|
_procsplx(s);
|
||||||
r = _threadrendezvous((ulong)&c, 0);
|
r = _threadrendezvous((ulong)&c, 0);
|
||||||
|
|||||||
@ -86,6 +86,7 @@ proccreate(void (*f)(void*), void *arg, uint stacksize)
|
|||||||
|
|
||||||
p = _threadgetproc();
|
p = _threadgetproc();
|
||||||
if(p->idle){
|
if(p->idle){
|
||||||
|
fprint(2, "cannot create procs once there is an idle thread\n");
|
||||||
werrstr("cannot create procs once there is an idle thread");
|
werrstr("cannot create procs once there is an idle thread");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -124,6 +125,7 @@ threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
|
|||||||
int id;
|
int id;
|
||||||
|
|
||||||
if(_threadprocs!=1){
|
if(_threadprocs!=1){
|
||||||
|
fprint(2, "cannot have idle thread in multi-proc program\n");
|
||||||
werrstr("cannot have idle thread in multi-proc program");
|
werrstr("cannot have idle thread in multi-proc program");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -153,6 +155,8 @@ _newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, i
|
|||||||
else
|
else
|
||||||
*_threadpq.tail = p;
|
*_threadpq.tail = p;
|
||||||
_threadpq.tail = &p->next;
|
_threadpq.tail = &p->next;
|
||||||
|
if(_threadprocs == 1)
|
||||||
|
_threadmultiproc();
|
||||||
_threadprocs++;
|
_threadprocs++;
|
||||||
unlock(&_threadpq.lock);
|
unlock(&_threadpq.lock);
|
||||||
return p;
|
return p;
|
||||||
|
|||||||
@ -2,28 +2,18 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
|
|
||||||
|
static void efork(int[3], int[2], char*, char**);
|
||||||
void
|
void
|
||||||
procexec(Channel *pidc, int fd[3], char *prog, char *args[])
|
threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
|
||||||
{
|
{
|
||||||
int n;
|
int pfd[2];
|
||||||
Proc *p;
|
int n, pid;
|
||||||
Thread *t;
|
char exitstr[ERRMAX];
|
||||||
|
|
||||||
_threaddebug(DBGEXEC, "procexec %s", prog);
|
_threaddebug(DBGEXEC, "threadexec %s", prog);
|
||||||
/* must be only thread in proc */
|
|
||||||
p = _threadgetproc();
|
|
||||||
t = p->thread;
|
|
||||||
if(p->threads.head != t || p->threads.head->nextt != nil){
|
|
||||||
werrstr("not only thread in proc");
|
|
||||||
Bad:
|
|
||||||
_threaddebug(DBGEXEC, "procexec bad %r");
|
|
||||||
if(pidc)
|
|
||||||
sendul(pidc, ~0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want procexec to behave like exec; if exec succeeds,
|
* We want threadexec to behave like exec; if exec succeeds,
|
||||||
* never return, and if it fails, return with errstr set.
|
* never return, and if it fails, return with errstr set.
|
||||||
* Unfortunately, the exec happens in another proc since
|
* Unfortunately, the exec happens in another proc since
|
||||||
* we have to wait for the exec'ed process to finish.
|
* we have to wait for the exec'ed process to finish.
|
||||||
@ -34,114 +24,77 @@ procexec(Channel *pidc, int fd[3], char *prog, char *args[])
|
|||||||
* then the proc doing the exec sends the errstr down the
|
* then the proc doing the exec sends the errstr down the
|
||||||
* pipe to us.
|
* pipe to us.
|
||||||
*/
|
*/
|
||||||
if(pipe(p->exec.fd) < 0)
|
if(pipe(pfd) < 0)
|
||||||
goto Bad;
|
goto Bad;
|
||||||
if(fcntl(p->exec.fd[0], F_SETFD, 1) < 0)
|
if(fcntl(pfd[0], F_SETFD, 1) < 0)
|
||||||
goto Bad;
|
goto Bad;
|
||||||
if(fcntl(p->exec.fd[1], F_SETFD, 1) < 0)
|
if(fcntl(pfd[1], F_SETFD, 1) < 0)
|
||||||
goto Bad;
|
goto Bad;
|
||||||
|
|
||||||
/* exec in parallel via the scheduler */
|
switch(pid = fork()){
|
||||||
assert(p->needexec==0);
|
case -1:
|
||||||
p->exec.prog = prog;
|
close(pfd[0]);
|
||||||
p->exec.args = args;
|
close(pfd[1]);
|
||||||
p->exec.stdfd = fd;
|
goto Bad;
|
||||||
p->needexec = 1;
|
case 0:
|
||||||
_sched();
|
efork(fd, pfd, prog, args);
|
||||||
|
_exit(0);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
close(p->exec.fd[1]);
|
close(pfd[1]);
|
||||||
if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */
|
if((n = read(pfd[0], exitstr, ERRMAX-1)) > 0){ /* exec failed */
|
||||||
p->exitstr[n] = '\0';
|
exitstr[n] = '\0';
|
||||||
errstr(p->exitstr, ERRMAX);
|
errstr(exitstr, ERRMAX);
|
||||||
close(p->exec.fd[0]);
|
close(pfd[0]);
|
||||||
goto Bad;
|
goto Bad;
|
||||||
}
|
}
|
||||||
close(p->exec.fd[0]);
|
close(pfd[0]);
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
if(fd[1] != fd[0])
|
if(fd[1] != fd[0])
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
if(fd[2] != fd[1] && fd[2] != fd[0])
|
if(fd[2] != fd[1] && fd[2] != fd[0])
|
||||||
close(fd[2]);
|
close(fd[2]);
|
||||||
if(pidc)
|
if(pidc)
|
||||||
sendul(pidc, t->ret);
|
sendul(pidc, pid);
|
||||||
|
|
||||||
_threaddebug(DBGEXEC, "procexec schedexecwait");
|
_threaddebug(DBGEXEC, "threadexec schedexecwait");
|
||||||
/* wait for exec'ed program, then exit */
|
threadexits(0);
|
||||||
_schedexecwait();
|
|
||||||
|
Bad:
|
||||||
|
_threaddebug(DBGEXEC, "threadexec bad %r");
|
||||||
|
if(pidc)
|
||||||
|
sendul(pidc, ~0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
procexecl(Channel *pidc, int fd[3], char *f, ...)
|
threadexecl(Channel *pidc, int fd[3], char *f, ...)
|
||||||
{
|
{
|
||||||
procexec(pidc, fd, f, &f+1);
|
threadexec(pidc, fd, f, &f+1);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_schedexecwait(void)
|
|
||||||
{
|
|
||||||
int pid;
|
|
||||||
Channel *c;
|
|
||||||
Proc *p;
|
|
||||||
Thread *t;
|
|
||||||
Waitmsg *w;
|
|
||||||
|
|
||||||
p = _threadgetproc();
|
|
||||||
t = p->thread;
|
|
||||||
pid = t->ret;
|
|
||||||
_threaddebug(DBGEXEC, "_schedexecwait %d", t->ret);
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
w = wait();
|
|
||||||
if(w == nil)
|
|
||||||
break;
|
|
||||||
if(w->pid == pid)
|
|
||||||
break;
|
|
||||||
free(w);
|
|
||||||
}
|
|
||||||
if(w != nil){
|
|
||||||
if((c = _threadwaitchan) != nil)
|
|
||||||
sendp(c, w);
|
|
||||||
else
|
|
||||||
free(w);
|
|
||||||
}
|
|
||||||
threadexits("procexec");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
efork(void *ve)
|
efork(int stdfd[3], int fd[2], char *prog, char **args)
|
||||||
{
|
{
|
||||||
char buf[ERRMAX];
|
char buf[ERRMAX];
|
||||||
Execargs *e;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
e = ve;
|
_threaddebug(DBGEXEC, "_schedexec %s -- calling execv", prog);
|
||||||
_threaddebug(DBGEXEC, "_schedexec %s -- calling execv", e->prog);
|
dup(stdfd[0], 0);
|
||||||
dup(e->stdfd[0], 0);
|
dup(stdfd[1], 1);
|
||||||
dup(e->stdfd[1], 1);
|
dup(stdfd[2], 2);
|
||||||
dup(e->stdfd[2], 2);
|
|
||||||
for(i=3; i<40; i++)
|
for(i=3; i<40; i++)
|
||||||
if(i != e->fd[1])
|
if(i != fd[1])
|
||||||
close(i);
|
close(i);
|
||||||
rfork(RFNOTEG);
|
rfork(RFNOTEG);
|
||||||
execvp(e->prog, e->args);
|
execvp(prog, args);
|
||||||
_threaddebug(DBGEXEC, "_schedexec failed: %r");
|
_threaddebug(DBGEXEC, "_schedexec failed: %r");
|
||||||
rerrstr(buf, sizeof buf);
|
rerrstr(buf, sizeof buf);
|
||||||
if(buf[0]=='\0')
|
if(buf[0]=='\0')
|
||||||
strcpy(buf, "exec failed");
|
strcpy(buf, "exec failed");
|
||||||
write(e->fd[1], buf, strlen(buf));
|
write(fd[1], buf, strlen(buf));
|
||||||
close(e->fd[1]);
|
close(fd[1]);
|
||||||
_exits(buf);
|
_exits(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
_schedexec(Execargs *e)
|
|
||||||
{
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
if(pid == 0){
|
|
||||||
efork(e);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -24,6 +24,12 @@ _threaddie(int x)
|
|||||||
exit(_threadexitsallstatus[0] ? 1 : 0);
|
exit(_threadexitsallstatus[0] ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_nop(int x)
|
||||||
|
{
|
||||||
|
USED(x);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -31,6 +37,7 @@ main(int argc, char **argv)
|
|||||||
Proc *p;
|
Proc *p;
|
||||||
|
|
||||||
signal(SIGTERM, _threaddie);
|
signal(SIGTERM, _threaddie);
|
||||||
|
signal(SIGCHLD, _nop);
|
||||||
// rfork(RFREND);
|
// rfork(RFREND);
|
||||||
|
|
||||||
//_threaddebuglevel = (DBGSCHED|DBGCHAN|DBGREND)^~0;
|
//_threaddebuglevel = (DBGSCHED|DBGCHAN|DBGREND)^~0;
|
||||||
|
|||||||
@ -12,6 +12,7 @@ OFILES=\
|
|||||||
debug.$O\
|
debug.$O\
|
||||||
exec-unix.$O\
|
exec-unix.$O\
|
||||||
exit.$O\
|
exit.$O\
|
||||||
|
fdwait.$O\
|
||||||
getpid.$O\
|
getpid.$O\
|
||||||
id.$O\
|
id.$O\
|
||||||
iocall.$O\
|
iocall.$O\
|
||||||
@ -30,6 +31,7 @@ OFILES=\
|
|||||||
memsetd.$O\
|
memsetd.$O\
|
||||||
note.$O\
|
note.$O\
|
||||||
proctab.$O\
|
proctab.$O\
|
||||||
|
read9pmsg.$O\
|
||||||
ref.$O\
|
ref.$O\
|
||||||
rendez.$O\
|
rendez.$O\
|
||||||
sched.$O\
|
sched.$O\
|
||||||
|
|||||||
@ -6,6 +6,18 @@ enum
|
|||||||
PTABHASH = 257,
|
PTABHASH = 257,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int multi;
|
||||||
|
static Proc *theproc;
|
||||||
|
|
||||||
|
void
|
||||||
|
_threadmultiproc(void)
|
||||||
|
{
|
||||||
|
if(multi == 0){
|
||||||
|
multi = 1;
|
||||||
|
_threadsetproc(theproc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Lock ptablock;
|
static Lock ptablock;
|
||||||
Proc *ptab[PTABHASH];
|
Proc *ptab[PTABHASH];
|
||||||
|
|
||||||
@ -14,6 +26,10 @@ _threadsetproc(Proc *p)
|
|||||||
{
|
{
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
|
if(!multi){
|
||||||
|
theproc = p;
|
||||||
|
return;
|
||||||
|
}
|
||||||
lock(&ptablock);
|
lock(&ptablock);
|
||||||
h = ((unsigned)p->pid)%PTABHASH;
|
h = ((unsigned)p->pid)%PTABHASH;
|
||||||
p->link = ptab[h];
|
p->link = ptab[h];
|
||||||
@ -27,6 +43,9 @@ __threadgetproc(int rm)
|
|||||||
Proc **l, *p;
|
Proc **l, *p;
|
||||||
int h, pid;
|
int h, pid;
|
||||||
|
|
||||||
|
if(!multi)
|
||||||
|
return theproc;
|
||||||
|
|
||||||
pid = _threadgetpid();
|
pid = _threadgetpid();
|
||||||
|
|
||||||
lock(&ptablock);
|
lock(&ptablock);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
|
|
||||||
//static Thread *runthread(Proc*);
|
//static Thread *runthread(Proc*);
|
||||||
@ -67,10 +68,12 @@ _schedinit(void *arg)
|
|||||||
t = nil;
|
t = nil;
|
||||||
_sched();
|
_sched();
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if(p->needexec){
|
if(p->needexec){
|
||||||
t->ret = _schedexec(&p->exec);
|
t->ret = _schedexec(&p->exec);
|
||||||
p->needexec = 0;
|
p->needexec = 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if(p->newproc){
|
if(p->newproc){
|
||||||
t->ret = _schedfork(p->newproc);
|
t->ret = _schedfork(p->newproc);
|
||||||
if(t->ret < 0){
|
if(t->ret < 0){
|
||||||
@ -90,14 +93,45 @@ _schedinit(void *arg)
|
|||||||
static Thread*
|
static Thread*
|
||||||
runthread(Proc *p)
|
runthread(Proc *p)
|
||||||
{
|
{
|
||||||
|
Channel *c;
|
||||||
Thread *t;
|
Thread *t;
|
||||||
Tqueue *q;
|
Tqueue *q;
|
||||||
|
Waitmsg *w;
|
||||||
|
int e, sent;
|
||||||
|
|
||||||
if(p->nthreads==0 || (p->nthreads==1 && p->idle))
|
if(p->nthreads==0 || (p->nthreads==1 && p->idle))
|
||||||
return nil;
|
return nil;
|
||||||
q = &p->ready;
|
q = &p->ready;
|
||||||
|
relock:
|
||||||
lock(&p->readylock);
|
lock(&p->readylock);
|
||||||
if(q->head == nil){
|
if(q->head == nil){
|
||||||
|
e = errno;
|
||||||
|
if((c = _threadwaitchan) != nil){
|
||||||
|
if(c->n <= c->s){
|
||||||
|
sent = 0;
|
||||||
|
for(;;){
|
||||||
|
if((w = p->waitmsg) != nil)
|
||||||
|
p->waitmsg = nil;
|
||||||
|
else
|
||||||
|
w = waitnohang();
|
||||||
|
if(w == nil)
|
||||||
|
break;
|
||||||
|
if(sent == 0){
|
||||||
|
unlock(&p->readylock);
|
||||||
|
sent = 1;
|
||||||
|
}
|
||||||
|
if(nbsendp(c, w) != 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p->waitmsg = w;
|
||||||
|
if(sent)
|
||||||
|
goto relock;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
while((w = waitnohang()) != nil)
|
||||||
|
free(w);
|
||||||
|
}
|
||||||
|
errno = e;
|
||||||
if(p->idle){
|
if(p->idle){
|
||||||
if(p->idle->state != Ready){
|
if(p->idle->state != Ready){
|
||||||
fprint(2, "everyone is asleep\n");
|
fprint(2, "everyone is asleep\n");
|
||||||
|
|||||||
@ -139,6 +139,7 @@ struct Proc
|
|||||||
void *arg; /* passed between shared and unshared stk */
|
void *arg; /* passed between shared and unshared stk */
|
||||||
char str[ERRMAX]; /* used by threadexits to avoid malloc */
|
char str[ERRMAX]; /* used by threadexits to avoid malloc */
|
||||||
char errbuf[ERRMAX]; /* errstr */
|
char errbuf[ERRMAX]; /* errstr */
|
||||||
|
Waitmsg *waitmsg;
|
||||||
|
|
||||||
void* udata; /* User per-proc data pointer */
|
void* udata; /* User per-proc data pointer */
|
||||||
};
|
};
|
||||||
@ -181,6 +182,7 @@ void __threaddebug(ulong, char*, ...);
|
|||||||
void _threadexitsall(char*);
|
void _threadexitsall(char*);
|
||||||
void _threadflagrendez(Thread*);
|
void _threadflagrendez(Thread*);
|
||||||
Proc* _threadgetproc(void);
|
Proc* _threadgetproc(void);
|
||||||
|
extern void _threadmultiproc(void);
|
||||||
Proc* _threaddelproc(void);
|
Proc* _threaddelproc(void);
|
||||||
void _threadsetproc(Proc*);
|
void _threadsetproc(Proc*);
|
||||||
void _threadinitstack(Thread*, void(*)(void*), void*);
|
void _threadinitstack(Thread*, void(*)(void*), void*);
|
||||||
@ -195,7 +197,6 @@ long _xdec(long*);
|
|||||||
void _xinc(long*);
|
void _xinc(long*);
|
||||||
void _threadremove(Proc*, Thread*);
|
void _threadremove(Proc*, Thread*);
|
||||||
|
|
||||||
extern int _threadmultiproc;
|
|
||||||
extern int _threaddebuglevel;
|
extern int _threaddebuglevel;
|
||||||
extern char* _threadexitsallstatus;
|
extern char* _threadexitsallstatus;
|
||||||
extern Pqueue _threadpq;
|
extern Pqueue _threadpq;
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 1998-2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 1998-2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 1998-2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
|
|
||||||
#define nil ((void*)0)
|
|
||||||
|
|
||||||
#define uchar _fmtuchar
|
|
||||||
#define ushort _fmtushort
|
|
||||||
#define uint _fmtuint
|
|
||||||
#define ulong _fmtulong
|
|
||||||
#define vlong _fmtvlong
|
|
||||||
#define uvlong _fmtuvlong
|
|
||||||
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
typedef unsigned short ushort;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef unsigned long ulong;
|
|
||||||
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
PLAN9=../..
|
|
||||||
<$PLAN9/src/mkhdr
|
|
||||||
|
|
||||||
LIB=libutf.a
|
|
||||||
|
|
||||||
OFILES=\
|
|
||||||
rune.$O\
|
|
||||||
runestrcat.$O\
|
|
||||||
runestrchr.$O\
|
|
||||||
runestrcmp.$O\
|
|
||||||
runestrcpy.$O\
|
|
||||||
runestrdup.$O\
|
|
||||||
runestrlen.$O\
|
|
||||||
runestrecpy.$O\
|
|
||||||
runestrncat.$O\
|
|
||||||
runestrncmp.$O\
|
|
||||||
runestrncpy.$O\
|
|
||||||
runestrrchr.$O\
|
|
||||||
runestrstr.$O\
|
|
||||||
runetype.$O\
|
|
||||||
utfecpy.$O\
|
|
||||||
utflen.$O\
|
|
||||||
utfnlen.$O\
|
|
||||||
utfrrune.$O\
|
|
||||||
utfrune.$O\
|
|
||||||
utfutf.$O\
|
|
||||||
|
|
||||||
HFILES=\
|
|
||||||
$PLAN9/include/utf.h\
|
|
||||||
|
|
||||||
<$PLAN9/src/mksyslib
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
Bit1 = 7,
|
|
||||||
Bitx = 6,
|
|
||||||
Bit2 = 5,
|
|
||||||
Bit3 = 4,
|
|
||||||
Bit4 = 3,
|
|
||||||
|
|
||||||
T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
|
|
||||||
Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
|
|
||||||
T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
|
|
||||||
T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
|
|
||||||
T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
|
|
||||||
|
|
||||||
Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
|
|
||||||
Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
|
|
||||||
Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
|
|
||||||
|
|
||||||
Maskx = (1<<Bitx)-1, /* 0011 1111 */
|
|
||||||
Testx = Maskx ^ 0xFF, /* 1100 0000 */
|
|
||||||
|
|
||||||
Bad = Runeerror,
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
chartorune(Rune *rune, char *str)
|
|
||||||
{
|
|
||||||
int c, c1, c2;
|
|
||||||
long l;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* one character sequence
|
|
||||||
* 00000-0007F => T1
|
|
||||||
*/
|
|
||||||
c = *(uchar*)str;
|
|
||||||
if(c < Tx) {
|
|
||||||
*rune = c;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* two character sequence
|
|
||||||
* 0080-07FF => T2 Tx
|
|
||||||
*/
|
|
||||||
c1 = *(uchar*)(str+1) ^ Tx;
|
|
||||||
if(c1 & Testx)
|
|
||||||
goto bad;
|
|
||||||
if(c < T3) {
|
|
||||||
if(c < T2)
|
|
||||||
goto bad;
|
|
||||||
l = ((c << Bitx) | c1) & Rune2;
|
|
||||||
if(l <= Rune1)
|
|
||||||
goto bad;
|
|
||||||
*rune = l;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* three character sequence
|
|
||||||
* 0800-FFFF => T3 Tx Tx
|
|
||||||
*/
|
|
||||||
c2 = *(uchar*)(str+2) ^ Tx;
|
|
||||||
if(c2 & Testx)
|
|
||||||
goto bad;
|
|
||||||
if(c < T4) {
|
|
||||||
l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
|
|
||||||
if(l <= Rune2)
|
|
||||||
goto bad;
|
|
||||||
*rune = l;
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* bad decoding
|
|
||||||
*/
|
|
||||||
bad:
|
|
||||||
*rune = Bad;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
runetochar(char *str, Rune *rune)
|
|
||||||
{
|
|
||||||
long c;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* one character sequence
|
|
||||||
* 00000-0007F => 00-7F
|
|
||||||
*/
|
|
||||||
c = *rune;
|
|
||||||
if(c <= Rune1) {
|
|
||||||
str[0] = c;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* two character sequence
|
|
||||||
* 0080-07FF => T2 Tx
|
|
||||||
*/
|
|
||||||
if(c <= Rune2) {
|
|
||||||
str[0] = T2 | (c >> 1*Bitx);
|
|
||||||
str[1] = Tx | (c & Maskx);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* three character sequence
|
|
||||||
* 0800-FFFF => T3 Tx Tx
|
|
||||||
*/
|
|
||||||
str[0] = T3 | (c >> 2*Bitx);
|
|
||||||
str[1] = Tx | ((c >> 1*Bitx) & Maskx);
|
|
||||||
str[2] = Tx | (c & Maskx);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
runelen(long c)
|
|
||||||
{
|
|
||||||
Rune rune;
|
|
||||||
char str[10];
|
|
||||||
|
|
||||||
rune = c;
|
|
||||||
return runetochar(str, &rune);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
runenlen(Rune *r, int nrune)
|
|
||||||
{
|
|
||||||
int nb, c;
|
|
||||||
|
|
||||||
nb = 0;
|
|
||||||
while(nrune--) {
|
|
||||||
c = *r++;
|
|
||||||
if(c <= Rune1)
|
|
||||||
nb++;
|
|
||||||
else
|
|
||||||
if(c <= Rune2)
|
|
||||||
nb += 2;
|
|
||||||
else
|
|
||||||
nb += 3;
|
|
||||||
}
|
|
||||||
return nb;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fullrune(char *str, int n)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
|
|
||||||
if(n > 0) {
|
|
||||||
c = *(uchar*)str;
|
|
||||||
if(c < Tx)
|
|
||||||
return 1;
|
|
||||||
if(n > 1)
|
|
||||||
if(c < T3 || n > 2)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrcat(Rune *s1, Rune *s2)
|
|
||||||
{
|
|
||||||
|
|
||||||
runestrcpy(runestrchr(s1, 0), s2);
|
|
||||||
return s1;
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrchr(Rune *s, Rune c)
|
|
||||||
{
|
|
||||||
Rune c0 = c;
|
|
||||||
Rune c1;
|
|
||||||
|
|
||||||
if(c == 0) {
|
|
||||||
while(*s++)
|
|
||||||
;
|
|
||||||
return s-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(c1 = *s++)
|
|
||||||
if(c1 == c0)
|
|
||||||
return s-1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
runestrcmp(Rune *s1, Rune *s2)
|
|
||||||
{
|
|
||||||
Rune c1, c2;
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
c1 = *s1++;
|
|
||||||
c2 = *s2++;
|
|
||||||
if(c1 != c2) {
|
|
||||||
if(c1 > c2)
|
|
||||||
return 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(c1 == 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrcpy(Rune *s1, Rune *s2)
|
|
||||||
{
|
|
||||||
Rune *os1;
|
|
||||||
|
|
||||||
os1 = s1;
|
|
||||||
while(*s1++ = *s2++)
|
|
||||||
;
|
|
||||||
return os1;
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrdup(Rune *s)
|
|
||||||
{
|
|
||||||
Rune *ns;
|
|
||||||
|
|
||||||
ns = malloc(sizeof(Rune)*(runestrlen(s) + 1));
|
|
||||||
if(ns == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return runestrcpy(ns, s);
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrecpy(Rune *s1, Rune *es1, Rune *s2)
|
|
||||||
{
|
|
||||||
if(s1 >= es1)
|
|
||||||
return s1;
|
|
||||||
|
|
||||||
while(*s1++ = *s2++){
|
|
||||||
if(s1 == es1){
|
|
||||||
*--s1 = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s1;
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
long
|
|
||||||
runestrlen(Rune *s)
|
|
||||||
{
|
|
||||||
|
|
||||||
return runestrchr(s, 0) - s;
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrncat(Rune *s1, Rune *s2, long n)
|
|
||||||
{
|
|
||||||
Rune *os1;
|
|
||||||
|
|
||||||
os1 = s1;
|
|
||||||
s1 = runestrchr(s1, 0);
|
|
||||||
while(*s1++ = *s2++)
|
|
||||||
if(--n < 0) {
|
|
||||||
s1[-1] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return os1;
|
|
||||||
}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
runestrncmp(Rune *s1, Rune *s2, long n)
|
|
||||||
{
|
|
||||||
Rune c1, c2;
|
|
||||||
|
|
||||||
while(n > 0) {
|
|
||||||
c1 = *s1++;
|
|
||||||
c2 = *s2++;
|
|
||||||
n--;
|
|
||||||
if(c1 != c2) {
|
|
||||||
if(c1 > c2)
|
|
||||||
return 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(c1 == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrncpy(Rune *s1, Rune *s2, long n)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Rune *os1;
|
|
||||||
|
|
||||||
os1 = s1;
|
|
||||||
for(i = 0; i < n; i++)
|
|
||||||
if((*s1++ = *s2++) == 0) {
|
|
||||||
while(++i < n)
|
|
||||||
*s1++ = 0;
|
|
||||||
return os1;
|
|
||||||
}
|
|
||||||
return os1;
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
Rune*
|
|
||||||
runestrrchr(Rune *s, Rune c)
|
|
||||||
{
|
|
||||||
Rune *r;
|
|
||||||
|
|
||||||
if(c == 0)
|
|
||||||
return runestrchr(s, 0);
|
|
||||||
r = 0;
|
|
||||||
while(s = runestrchr(s, c))
|
|
||||||
r = s++;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* The authors of this software are Rob Pike and Ken Thompson.
|
|
||||||
* Copyright (c) 2002 by Lucent Technologies.
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
* is included in all copies of any software which is or includes a copy
|
|
||||||
* or modification of this software and in all copies of the supporting
|
|
||||||
* documentation for such software.
|
|
||||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
|
||||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
|
||||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "utf.h"
|
|
||||||
#include "utfdef.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return pointer to first occurrence of s2 in s1,
|
|
||||||
* 0 if none
|
|
||||||
*/
|
|
||||||
Rune*
|
|
||||||
runestrstr(Rune *s1, Rune *s2)
|
|
||||||
{
|
|
||||||
Rune *p, *pa, *pb;
|
|
||||||
int c0, c;
|
|
||||||
|
|
||||||
c0 = *s2;
|
|
||||||
if(c0 == 0)
|
|
||||||
return s1;
|
|
||||||
s2++;
|
|
||||||
for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) {
|
|
||||||
pa = p;
|
|
||||||
for(pb=s2;; pb++) {
|
|
||||||
c = *pb;
|
|
||||||
if(c == 0)
|
|
||||||
return p;
|
|
||||||
if(c != *++pa)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,14 +0,0 @@
|
|||||||
#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)
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user