Add Plan 9 formatted IO. Various cleanups and fixes.

This commit is contained in:
Kris Maglione 2007-07-01 07:08:30 -04:00
parent 29cd363e63
commit 209fb08f82
141 changed files with 10588 additions and 590 deletions

View File

@ -7,6 +7,10 @@ PDIRS = \
man
DIRS = \
libutf \
libfmt \
libbio \
libregexp\
${PDIRS}
config:

View File

@ -17,6 +17,7 @@ FILTER = sed "s|CONFPREFIX|${ETC}|g; \
s|P9PATHS|${P9PATHS}|g; \
s|AWKPATH|${AWKPATH}|g"
LDFLAGS += -lbio -lfmt -lutf
CFLAGS += ${INCX11} -DVERSION=\"${VERSION}\"
include ${ROOT}/mk/many.mk

View File

@ -6,25 +6,29 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fmt.h>
#include <util.h>
static int
Vfmt(Fmt *f) {
char *fmt;
va_list ap;
fmt = va_arg(f->args, char*);
ap = va_arg(f->args, va_list);
return fmtvprint(f, fmt, ap);
}
void
fatal(const char *fmt, ...) {
va_list ap;
int err;
err = errno;
fprintf(stderr, "%s: fatal: ", argv0);
fmtinstall('V', Vfmt);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
fprint(2, "%s: fatal: %V\n", argv0, fmt, ap);
va_end(ap);
if(fmt[strlen(fmt)-1] == ':')
fprintf(stderr, " %s\n", strerror(err));
else
fprintf(stderr, "\n");
exit(1);
}
@ -35,6 +39,7 @@ mfatal(char *name, uint size) {
couldnot[] = ": fatal: Could not ",
paren[] = "() ",
bytes[] = " bytes\n";
char buf[1024];
char sizestr[8];
int i;
@ -44,12 +49,13 @@ mfatal(char *name, uint size) {
size /= 10;
} while(size > 0);
write(1, argv0, strlen(argv0)-1);
write(1, couldnot, sizeof(couldnot)-1);
write(1, name, strlen(name));
write(1, paren, sizeof(paren)-1);
write(1, sizestr+i, sizeof(sizestr)-i);
write(1, bytes, sizeof(bytes)-1);
strlcat(buf, argv0, sizeof(buf));
strlcat(buf, couldnot, sizeof(buf));
strlcat(buf, name, sizeof(buf));
strlcat(buf, paren, sizeof(buf));
strlcat(buf, sizestr+i, sizeof(buf));
strlcat(buf, bytes, sizeof(buf));
write(2, buf, strlen(buf));
exit(1);
}

View File

@ -5,10 +5,10 @@ include ${ROOT}/mk/wmii.mk
main.c: ${ROOT}/mk/wmii.mk
TARG = wmii
HFILES= dat.h fns.h utf.h x11.h
HFILES= dat.h fns.h x11.h
LIB = ${LIBIXP}
LDFLAGS += -lm ${LIBX11} -lXext ${LIBICONV}
LDFLAGS += -lm ${LIBX11} -lXext ${LIBICONV} -lregexp9 -lbio -lfmt -lutf
CFLAGS += ${INCX11} ${INCICONV} -DVERSION=\"${VERSION}\"
OBJ = area \
bar \

View File

@ -38,7 +38,7 @@ area_name(Area *a) {
if(a->floating)
return "~";
snprintf(buf, sizeof(buf), "%d", area_idx(a));
snprint(buf, sizeof(buf), "%d", area_idx(a));
return buf;
}

View File

@ -114,8 +114,8 @@ draw_bar(WMScreen *s) {
width += Dx(b->r);
}
/* Not enough room. Shrink bars until they all fit */
if(width > Dx(s->brect)) {
if(width > Dx(s->brect)) { /* Not enough room. Shrink bars until they all fit. */
for(nb = 0; nb < nelem(s->bar); nb++)
for(b = s->bar[nb]; b; b=b->next) {
for(pb = &largest; *pb; pb = &(*pb)->smaller)

View File

@ -81,7 +81,7 @@ create_client(XWindow w, XWindowAttributes *wa) {
break;
}
write_event("CreateClient 0x%x\n", c->w.w);
write_event("CreateClient %C\n", c);
manage_client(c);
return c;
}
@ -134,7 +134,7 @@ destroy_client(Client *c) {
Client **tc;
Bool hide;
Debug fprintf(stderr, "client.c:destroy_client(%p) %s\n", c, c->name);
Dprint("client.c:destroy_client(%p) %s\n", c, c->name);
unmapwin(c->framewin);
@ -172,9 +172,10 @@ destroy_client(Client *c) {
XSetErrorHandler(handler);
XUngrabServer(display);
write_event("DestroyClient 0x%x\n", clientwin(c));
write_event("DestroyClient %C\n", c);
flushevents(EnterWindowMask, False);
free(c->w.hints);
free(c);
}
@ -194,11 +195,14 @@ win2client(XWindow w) {
return c;
}
uint
clientwin(Client *c) {
int
Cfmt(Fmt *f) {
Client *c;
c = va_arg(f->args, Client*);
if(c)
return (uint)c->w.w;
return 0;
return fmtprint(f, "%W", &c->w);
return fmtprint(f, "<nil>");
}
char *
@ -222,13 +226,14 @@ gravclient(Client *c, Rectangle rd) {
r = c->sel->r;
else
r = c->sel->revert;
r = gravitate(c->r, r, h->grav);
r = gravitate(r, c->r, h->grav);
if(h->gravstatic)
r = rectaddpt(r, sp);
return frame2client(nil, r);
r = frame2client(nil, r);
return r;
}else {
r = client2frame(nil, rd);
r = gravitate(r, rd, h->grav);
r = gravitate(rd, r, h->grav);
if(h->gravstatic)
r = rectsubpt(r, sp);
return r;
@ -319,17 +324,17 @@ void
focus_client(Client *c) {
flushevents(FocusChangeMask, True);
Debug fprintf(stderr, "focus_client(%p[%x]) => %s\n", c, clientwin(c), clientname(c));
Dprint("focus_client(%p[%C]) => %s\n", c, c, clientname(c));
if((c == nil || !c->noinput) && screen->focus != c) {
Debug fprintf(stderr, "\t%s => %s\n", clientname(screen->focus), clientname(c));
Dprint("\t%s => %s\n", clientname(screen->focus), clientname(c));
if(c)
setfocus(&c->w, RevertToParent);
else
setfocus(screen->barwin, RevertToParent);
write_event("ClientFocus 0x%x\n", clientwin(c));
write_event("ClientFocus %C\n", c);
XSync(display, False);
flushevents(FocusChangeMask, True);
@ -460,7 +465,7 @@ set_urgent(Client *c, Bool urgent, Bool write) {
cnot = (urgent ? "" : "Not");
if(urgent != c->urgent) {
write_event("%sUrgent 0x%x %s\n", cnot, clientwin(c), cwrite);
write_event("%sUrgent %C %s\n", cnot, c, cwrite);
c->urgent = urgent;
if(c->sel) {
if(c->sel->view == screen->sel)
@ -594,7 +599,7 @@ prop_client(Client *c, Atom a) {
break;
case XA_WM_CLASS:
n = gettextlistproperty(&c->w, "WM_CLASS", &class);
snprintf(c->props, sizeof(c->props), "%s:%s:",
snprint(c->props, sizeof(c->props), "%s:%s:",
(n > 0 ? class[0] : "<nil>"),
(n > 1 ? class[1] : "<nil>"));
freestringlist(class);
@ -649,7 +654,7 @@ configreq_event(Window *w, XConfigureRequestEvent *e) {
static void
destroy_event(Window *w, XDestroyWindowEvent *e) {
Debug fprintf(stderr, "client.c:destroy_event(%x)\n", (uint)w->w);
Dprint("client.c:destroy_event(%W)\n", w);
destroy_client(w->aux);
}
@ -660,12 +665,11 @@ enter_event(Window *w, XCrossingEvent *e) {
c = w->aux;
if(e->detail != NotifyInferior) {
if(screen->focus != c) {
Debug fprintf(stderr, "enter_notify(c) => %s\n", c->name);
Dprint("enter_notify(c) => %s\n", c->name);
focus(c, False);
}
set_cursor(c, cursor[CurNormal]);
}else Debug
fprintf(stderr, "enter_notify(c[NotifyInferior]) => %s\n", c->name);
}else Dprint("enter_notify(c[NotifyInferior]) => %s\n", c->name);
}
static void
@ -922,14 +926,13 @@ apply_tags(Client *c, const char *tags) {
void
apply_rules(Client *c) {
Rule *r;
regmatch_t rm;
if(strlen(c->tags))
return;
if(def.tagrules.string)
for(r=def.tagrules.rule; r; r=r->next)
if(!regexec(&r->regex, c->props, 1, &rm, 0)) {
if(regexec(r->regex, c->props, nil, 0)) {
apply_tags(c, r->value);
if(c->tags[0] && strcmp(c->tags, "nil"))
break;
@ -937,3 +940,4 @@ apply_rules(Client *c) {
if(c->tags[0] == '\0')
apply_tags(c, "nil");
}

View File

@ -2,9 +2,12 @@
* See LICENSE file for license details.
*/
#include <regex.h>
#include <regexp9.h>
#define IXP_P9_STRUCTS
#define IXP_NO_P9_
#include <ixp.h>
#include <utf.h>
#include <fmt.h>
#include "x11.h"
#define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*"
@ -172,7 +175,7 @@ struct Bar {
struct Rule {
Rule *next;
regex_t regex;
Reprog *regex;
char value[256];
};
@ -248,4 +251,5 @@ char *user;
char *execstr;
#define Debug if(verbose)
#define Dprint(...) do{ Debug fprint(2, __VA_ARGS__); }while(0)

View File

@ -83,10 +83,10 @@ destroynotify(XEvent *e) {
if((w = findwin(ev->window)))
handle(w, destroy, ev);
else {
Debug fprintf(stderr, "DestroyWindow(%x) (no handler)\n", (uint)ev->window);
Dprint("DestroyWindow(%ux) (no handler)\n", (uint)ev->window);
if((c = win2client(ev->window)))
fprintf(stderr, "Badness: Unhandled DestroyNotify: "
"Client: %p, Window: %x, Name: %s\n", c, (uint)c->w.w, c->name);
fprint(2, "Badness: Unhandled DestroyNotify: "
"Client: %p, Window: %W, Name: %s\n", c, &c->w, c->name);
}
}
@ -122,11 +122,9 @@ leavenotify(XEvent *e) {
void
print_focus(Client *c, char *to) {
Debug {
fprintf(stderr, "screen->focus: %p[%x] => %p[%x]\n",
screen->focus, clientwin(screen->focus), c, clientwin(c));
fprintf(stderr, "\t%s => %s\n", clientname(screen->focus), to);
}
Dprint("screen->focus: %p[%C] => %p[%C]\n",
screen->focus, screen->focus, c, c);
Dprint("\t%s => %s\n", clientname(screen->focus), to);
}
static void

View File

@ -49,7 +49,7 @@ void move_client(Client*, char *arg);
void size_client(Client*, char *arg);
Client *selclient(void);
Client *win2client(XWindow);
uint clientwin(Client *c);
int Cfmt(Fmt *f);
char *clientname(Client*);
void apply_rules(Client*);
void apply_tags(Client*, const char*);
@ -123,15 +123,15 @@ void* maprm(Map*, ulong);
void* hashrm(Map*, char*);
/* message.c */
char * getword(Message*);
char * getword(IxpMsg*);
Area * strarea(View*, char*);
char * message_view(View*, Message*);
char * parse_colors(Message*, CTuple*);
char * message_root(void*, Message*);
char * message_view(View*, IxpMsg*);
char * parse_colors(IxpMsg*, CTuple*);
char * message_root(void*, IxpMsg*);
char * read_root_ctl(void);
char * message_client(Client*, Message*);
char *select_area(Area*, Message*);
char *send_client(View*, Message*, Bool swap);
char * message_client(Client*, IxpMsg*);
char *select_area(Area*, IxpMsg*);
char *send_client(View*, IxpMsg*, Bool swap);
/* mouse.c */
void mouse_resizecol(Divide*);
@ -158,7 +158,7 @@ Frame *view_clientframe(View *v, Client *c);
void select_view(const char*);
void attach_to_view(View*, Frame*);
Client *view_selclient(View*);
char *message_view(View *v, Message *m);
char *message_view(View *v, IxpMsg *m);
void restack_view(View*);
uchar *view_index(View*);
uchar *view_ctl(View *v);

View File

@ -116,7 +116,7 @@ frame_to_top(Frame *f) {
/* Handlers */
static void
bup_event(Window *w, XButtonEvent *e) {
write_event("ClientClick 0x%x %d\n", (uint)w->w, e->button);
write_event("ClientClick %C %d\n", w->aux, e->button);
}
static void
@ -166,7 +166,7 @@ bdown_event(Window *w, XButtonEvent *e) {
XUngrabPointer(display, e->time);
XSync(display, False);
write_event("ClientMouseDown 0x%x %d\n", f->client->w.w, e->button);
write_event("ClientMouseDown %C %d\n", f->client, e->button);
}
}
}
@ -179,7 +179,7 @@ enter_event(Window *w, XCrossingEvent *e) {
c = w->aux;
f = c->sel;
if(screen->focus != c) {
Debug fprintf(stderr, "enter_notify(f) => %s\n", f->client->name);
Dprint("enter_notify(f) => %s\n", f->client->name);
if(f->area->floating || !f->collapsed)
focus(f->client, False);
}
@ -194,8 +194,8 @@ expose_event(Window *w, XExposeEvent *e) {
if(c->sel)
draw_frame(c->sel);
else
fprintf(stderr, "Badness: Expose event on a client frame which shouldn't be visible: %x\n",
(uint)c->w.w);
fprint(2, "Badness: Expose event on a client frame which shouldn't be visible: %C\n",
c);
}
static void
@ -268,8 +268,7 @@ resize_frame(Frame *f, Rectangle r) {
f->crect = frame_hints(f, r, stickycorner);
if(Dx(r) <= 0 || Dy(r) <= 0)
fprintf(stderr, "Badness: Frame rect: %d,%d %dx%d\n",
r.min.x, r.min.y, Dx(r), Dy(r));
fprint(2, "Badness: Frame rect: %R\n", r);
if(f->area->floating)
f->r = f->crect;

View File

@ -96,34 +96,34 @@ Ixp9Srv p9srv = {
* in by lookup_file
*/
static Dirtab
dirtab_root[]= {{".", QTDIR, FsRoot, 0500|P9_DMDIR },
{"rbar", QTDIR, FsDBars, 0700|P9_DMDIR },
{"lbar", QTDIR, FsDBars, 0700|P9_DMDIR },
{"client", QTDIR, FsDClients, 0500|P9_DMDIR },
{"tag", QTDIR, FsDTags, 0500|P9_DMDIR },
{"ctl", QTAPPEND, FsFRctl, 0600|P9_DMAPPEND },
dirtab_root[]= {{".", QTDIR, FsRoot, 0500|DMDIR },
{"rbar", QTDIR, FsDBars, 0700|DMDIR },
{"lbar", QTDIR, FsDBars, 0700|DMDIR },
{"client", QTDIR, FsDClients, 0500|DMDIR },
{"tag", QTDIR, FsDTags, 0500|DMDIR },
{"ctl", QTAPPEND, FsFRctl, 0600|DMAPPEND },
{"colrules", QTFILE, FsFColRules, 0600 },
{"event", QTFILE, FsFEvent, 0600 },
{"keys", QTFILE, FsFKeys, 0600 },
{"tagrules", QTFILE, FsFTagRules, 0600 },
{nil}},
dirtab_clients[]={{".", QTDIR, FsDClients, 0500|P9_DMDIR },
{"", QTDIR, FsDClient, 0500|P9_DMDIR },
dirtab_clients[]={{".", QTDIR, FsDClients, 0500|DMDIR },
{"", QTDIR, FsDClient, 0500|DMDIR },
{nil}},
dirtab_client[]= {{".", QTDIR, FsDClient, 0500|P9_DMDIR },
{"ctl", QTAPPEND, FsFCctl, 0600|P9_DMAPPEND },
dirtab_client[]= {{".", QTDIR, FsDClient, 0500|DMDIR },
{"ctl", QTAPPEND, FsFCctl, 0600|DMAPPEND },
{"label", QTFILE, FsFClabel, 0600 },
{"tags", QTFILE, FsFCtags, 0600 },
{"props", QTFILE, FsFprops, 0400 },
{nil}},
dirtab_bars[]= {{".", QTDIR, FsDBars, 0700|P9_DMDIR },
dirtab_bars[]= {{".", QTDIR, FsDBars, 0700|DMDIR },
{"", QTFILE, FsFBar, 0600 },
{nil}},
dirtab_tags[]= {{".", QTDIR, FsDTags, 0500|P9_DMDIR },
{"", QTDIR, FsDTag, 0500|P9_DMDIR },
dirtab_tags[]= {{".", QTDIR, FsDTags, 0500|DMDIR },
{"", QTDIR, FsDTag, 0500|DMDIR },
{nil}},
dirtab_tag[]= {{".", QTDIR, FsDTag, 0500|P9_DMDIR },
{"ctl", QTAPPEND, FsFTctl, 0600|P9_DMAPPEND },
dirtab_tag[]= {{".", QTDIR, FsDTag, 0500|DMDIR },
{"ctl", QTAPPEND, FsFTctl, 0600|DMAPPEND },
{"index", QTFILE, FsFTindex, 0400 },
{nil}};
static Dirtab *dirtab[] = {
@ -190,7 +190,7 @@ static void
write_to_buf(Ixp9Req *r, void *buf, uint *len, uint max) {
uint offset, count;
offset = (r->fid->omode&P9_OAPPEND) ? *len : r->ifcall.offset;
offset = (r->fid->omode&OAPPEND) ? *len : r->ifcall.offset;
if(offset > *len || r->ifcall.count == 0) {
r->ofcall.count = 0;
return;
@ -228,13 +228,13 @@ data_to_cstring(Ixp9Req *r) {
free(p);
}
typedef char* (*MsgFunc)(void*, Message*);
typedef char* (*MsgFunc)(void*, IxpMsg*);
static char *
message(Ixp9Req *r, MsgFunc fn) {
char *err, *s, *p, c;
FileId *f;
Message m;
IxpMsg m;
f = r->fid->aux;
@ -284,7 +284,7 @@ write_event(char *format, ...) {
Ixp9Req *req;
va_start(ap, format);
vsnprintf(buffer, sizeof(buffer), format, ap);
vsnprint(buffer, sizeof(buffer), format, ap);
va_end(ap);
len = strlen(buffer);
@ -338,7 +338,7 @@ lookup_file(FileId *parent, char *name)
Bar *b;
uint id;
if(!(parent->tab.perm & P9_DMDIR))
if(!(parent->tab.perm & DMDIR))
return nil;
dir = dirtab[parent->tab.type];
last = &ret;
@ -375,8 +375,8 @@ lookup_file(FileId *parent, char *name)
file->id = c->w.w;
file->index = c->w.w;
file->tab = *dir;
file->tab.name = emallocz(16);
snprintf(file->tab.name, 16, "0x%x", (uint)c->w.w);
file->tab.name = smprint("%C", c);
assert(file->tab.name);
if(name) goto LastItem;
}
}
@ -564,7 +564,7 @@ fs_size(FileId *f) {
void
fs_stat(Ixp9Req *r) {
Message m;
IxpMsg m;
Stat s;
int size;
uchar *buf;
@ -603,9 +603,9 @@ fs_read(Ixp9Req *r) {
return;
}
if(f->tab.perm & P9_DMDIR && f->tab.perm & 0400) {
if(f->tab.perm & DMDIR && f->tab.perm & 0400) {
Stat s;
Message m;
IxpMsg m;
offset = 0;
size = r->ifcall.count;
@ -671,10 +671,8 @@ fs_read(Ixp9Req *r) {
respond(r, nil);
return;
}
r->ofcall.data = emallocz(16);
n = snprintf(r->ofcall.data, 16, "0x%x", (uint)f->index);
assert(n >= 0);
r->ofcall.count = n;
r->ofcall.data = smprint("%C", f->p.client);
r->ofcall.count = strlen(r->ofcall.data); /* will die if nil */
respond(r, nil);
return;
case FsFTindex:
@ -798,19 +796,19 @@ fs_open(Ixp9Req *r) {
peventfid = fl;
break;
}
if((r->ifcall.mode&3) == P9_OEXEC) {
if((r->ifcall.mode&3) == OEXEC) {
respond(r, Enoperm);
return;
}
if((r->ifcall.mode&3) != P9_OREAD && !(f->tab.perm & 0200)) {
if((r->ifcall.mode&3) != OREAD && !(f->tab.perm & 0200)) {
respond(r, Enoperm);
return;
}
if((r->ifcall.mode&3) != P9_OWRITE && !(f->tab.perm & 0400)) {
if((r->ifcall.mode&3) != OWRITE && !(f->tab.perm & 0400)) {
respond(r, Enoperm);
return;
}
if((r->ifcall.mode&~(3|P9_OAPPEND|P9_OTRUNC))) {
if((r->ifcall.mode&~(3|OAPPEND|OTRUNC))) {
respond(r, Enoperm);
return;
}
@ -873,7 +871,7 @@ fs_clunk(Ixp9Req *r) {
FileId *f;
char *p, *q;
Client *c;
Message m;
IxpMsg m;
f = r->fid->aux;
if(!verify_file(f)) {

View File

@ -33,6 +33,11 @@ usage(void) {
fatal("usage: wmii [-a <address>] [-r <wmiirc>] [-v]\n");
}
static int
errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf());
}
static void
scan_wins(void) {
int i;
@ -76,7 +81,7 @@ ns_display(void) {
*s = '\0';
s = emalloc(strlen(disp) + strlen(user) + strlen("/tmp/ns..") + 1);
sprintf(s, "/tmp/ns.%s.%s", user, disp);
sprint(s, "/tmp/ns.%s.%s", user, disp);
free(disp);
return s;
@ -95,7 +100,7 @@ rmkdir(char *path, int mode) {
*p = '\0';
ret = mkdir(path, mode);
if((ret == -1) && (errno != EEXIST))
fatal("Can't create ns_path '%s':", path);
fatal("Can't create ns_path '%s': %r", path);
*p = c;
}
}
@ -123,7 +128,7 @@ init_ns(void) {
rmkdir(ns_path, 0700);
if(stat(ns_path, &st))
fatal("Can't stat ns_path '%s':", ns_path);
fatal("Can't stat ns_path '%s': %r", ns_path);
if(getuid() != st.st_uid)
fatal("ns_path '%s' exists but is not owned by you", ns_path);
if(st.st_mode & 077)
@ -136,7 +141,7 @@ init_environment(void) {
if(address == nil) {
address = emalloc(strlen(ns_path) + strlen("unix!/wmii") + 1);
sprintf(address, "unix!%s/wmii", ns_path);
sprint(address, "unix!%s/wmii", ns_path);
}
setenv("WMII_NS_DIR", ns_path, True);
@ -256,7 +261,7 @@ errorhandler(Display *dpy, XErrorEvent *error) {
&& (itab[i].ecode == 0 || itab[i].ecode == error->error_code))
return 0;
fprintf(stderr, "%s: fatal error: Xrequest code=%d, Xerror code=%d\n",
fprint(2, "%s: fatal error: Xrequest code=%d, Xerror code=%d\n",
argv0, error->request_code, error->error_code);
/* Try to cleanup, but only try once, in case we're called again */
@ -287,27 +292,37 @@ init_traps(void) {
int fd[2];
if(pipe(fd) != 0)
fatal("Can't pipe():");
fatal("Can't pipe(): %r");
/* Double fork hack */
switch(fork()) {
case -1:
fatal("Can't fork():");
fatal("Can't fork(): %r");
break; /* not reached */
case 0:
close(fd[1]);
close(ConnectionNumber(display));
setsid();
switch(fork()) {
case -1:
fatal("Can't fork(): %r");
break; /* not reached */
case 0:
exit(0);
break;
default:
close(fd[1]);
close(ConnectionNumber(display));
setsid();
display = XOpenDisplay(0);
if(!display)
fatal("Can't open display");
display = XOpenDisplay(0);
if(!display)
fatal("Can't open display");
/* Wait for parent to exit */
read(fd[0], buf, 1);
/* Wait for parent to exit */
read(fd[0], buf, 1);
XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime);
XCloseDisplay(display);
exit(0);
XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime);
XCloseDisplay(display);
exit(0);
}
default:
break;
}
@ -332,16 +347,16 @@ spawn_command(const char *cmd) {
/* Double fork hack */
switch(pid = fork()) {
case -1:
fatal("Can't fork:");
fatal("Can't fork: %r");
break; /* Not reached */
case 0:
switch(fork()) {
case -1:
fatal("Can't fork:");
fatal("Can't fork: %r");
break; /* Not reached */
case 0:
if(setsid() == -1)
fatal("Can't setsid:");
fatal("Can't setsid: %r");
close(sock);
close(ConnectionNumber(display));
@ -351,10 +366,10 @@ spawn_command(const char *cmd) {
/* Run through the user's shell as a login shell */
p = malloc((strlen(shell) + 2));
sprintf(p, "-%s", strrchr(shell, '/') + 1);
sprint(p, "-%s", strrchr(shell, '/') + 1);
execl(shell, p, "-c", cmd, nil);
fatal("Can't exec '%s':", cmd);
fatal("Can't exec '%s': %r", cmd);
break; /* Not reached */
default:
exit(0);
@ -380,17 +395,19 @@ closedisplay(IxpConn *c) {
int
main(int argc, char *argv[]) {
char *wmiirc, *str;
char *wmiirc;
WMScreen *s;
WinAttr wa;
int i;
ulong col;
fmtinstall('r', errfmt);
fmtinstall('C', Cfmt);
wmiirc = "wmiistartrc";
ARGBEGIN{
case 'v':
printf("%s", version);
print("%s", version);
exit(0);
case 'V':
verbose = True;
@ -431,7 +448,7 @@ main(int argc, char *argv[]) {
sock = ixp_announce(address);
if(sock < 0)
fatal("Can't create socket '%s': %s", address, errstr);
fatal("Can't create socket '%s': %r", address);
if(wmiirc)
spawn_command(wmiirc);
@ -477,14 +494,6 @@ main(int argc, char *argv[]) {
initbar(s);
}
str = "This app is broken. Disable its transparency feature.";
i = textwidth(def.font, str) + labelh(def.font);
broken = allocimage(i, labelh(def.font), scr.depth);
namedcolor("#ff0000", &col);
fill(broken, broken->r, scr.black);
drawstring(broken, def.font, broken->r, EAST, str, col);
screen->focus = nil;
setfocus(screen->barwin, RevertToParent);
@ -496,9 +505,9 @@ main(int argc, char *argv[]) {
write_event("FocusTag %s\n", screen->sel->name);
check_x_event(nil);
errstr = ixp_serverloop(&srv);
if(errstr)
fprintf(stderr, "%s: error: %s\n", argv0, errstr);
i = ixp_serverloop(&srv);
if(i)
fprint(2, "%s: error: %r\n", argv0);
cleanup();
@ -506,7 +515,5 @@ main(int argc, char *argv[]) {
raise(exitsignal);
if(execstr)
execl("/bin/sh", "sh", "-c", execstr, nil);
if(errstr)
return 1;
return 0;
return i;
}

View File

@ -97,7 +97,7 @@ getsym(char *s) {
}
static void
eatrunes(Message *m, int (*p)(Rune), int val) {
eatrunes(IxpMsg *m, int (*p)(Rune), int val) {
Rune r;
int n;
@ -112,7 +112,7 @@ eatrunes(Message *m, int (*p)(Rune), int val) {
}
char *
getword(Message *m) {
getword(IxpMsg *m) {
char *ret;
Rune r;
int n;
@ -220,7 +220,7 @@ strarea(View *v, char *s) {
}
char *
message_view(View *v, Message *m) {
message_view(View *v, IxpMsg *m) {
Area *a;
char *s;
int i;
@ -258,32 +258,39 @@ message_view(View *v, Message *m) {
}
char *
parse_colors(Message *m, CTuple *col) {
static regex_t reg;
static Bool compiled;
char c;
parse_colors(IxpMsg *m, CTuple *col) {
static char Ebad[] = "bad color string";
Rune r;
char c, *p;
int i, j;
if(!compiled) {
compiled = 1;
regcomp(&reg, "^#[0-9a-f]{6} #[0-9a-f]{6} #[0-9a-f]{6}([[:space:]]|$)",
REG_EXTENDED|REG_NOSUB|REG_ICASE);
/* '#%6x #%6x #%6x' */
p = m->pos;
for(i = 0; i < 3 && p < (char*)m->end; i++) {
if(*p++ != '#')
return Ebad;
for(j = 0; j < 6 && p < (char*)m->end; j++)
if(!ishexnumber(*p++))
return Ebad;
chartorune(&r, p);
if(i < 2 && r != ' ' || !(isspacerune(r) || *p == '\0'))
return Ebad;
if(i < 2)
p++;
}
if(m->pos + 23 > m->end || regexec(&reg, m->pos, 0, 0, 0))
return "bad value";
c = m->pos[23];
m->pos[23] = '\0';
c = *p;
*p = '\0';
loadcolor(col, m->pos);
m->pos[23] = c;
*p = c;
m->pos += 23;
m->pos = p;
eatrunes(m, isspacerune, 1);
return nil;
}
char *
message_root(void *p, Message *m) {
message_root(void *p, IxpMsg *m) {
Font *fn;
char *s, *ret;
ulong n;
@ -296,15 +303,14 @@ message_root(void *p, Message *m) {
srv.running = 0;
break;
case LEXEC:
execstr = emalloc(strlen(m->pos) + sizeof("exec "));
sprintf(execstr, "exec %s", m->pos);
execstr = smprint("exec %s", m->pos);
srv.running = 0;
break;
case LVIEW:
select_view(m->pos);
break;
case LSELCOLORS:
fprintf(stderr, "%s: warning: selcolors have been removed\n", argv0);
fprint(2, "%s: warning: selcolors have been removed\n", argv0);
return Ebadcmd;
case LFOCUSCOLORS:
ret = parse_colors(m, &def.focuscolor);
@ -350,20 +356,18 @@ read_root_ctl(void) {
char *b, *e;
b = buffer;
e = b + sizeof(buffer);
#define print(...) if(b < e) b += snprintf(b, e-b, __VA_ARGS__)
print("view %s\n", screen->sel->name);
print("focuscolors %s\n", def.focuscolor.colstr);
print("normcolors %s\n", def.normcolor.colstr);
print("font %s\n", def.font->name);
print("grabmod %s\n", def.grabmod);
print("border %d\n", def.border);
#undef print
e = b + sizeof(buffer) - 1;
b = seprint(b, e, "view %s\n", screen->sel->name);
b = seprint(b, e, "focuscolors %s\n", def.focuscolor.colstr);
b = seprint(b, e, "normcolors %s\n", def.normcolor.colstr);
b = seprint(b, e, "font %s\n", def.font->name);
b = seprint(b, e, "grabmod %s\n", def.grabmod);
b = seprint(b, e, "border %d\n", def.border);
return buffer;
}
char *
message_client(Client *c, Message *m) {
message_client(Client *c, IxpMsg *m) {
char *s;
s = getword(m);
@ -431,7 +435,7 @@ send_frame(Frame *f, int sym, Bool swap) {
}
char *
send_client(View *v, Message *m, Bool swap) {
send_client(View *v, IxpMsg *m, Bool swap) {
Area *to, *a;
Frame *f;
Client *c;
@ -511,7 +515,7 @@ send_client(View *v, Message *m, Bool swap) {
}
static char*
select_frame(Frame *f, Message *m, int sym) {
select_frame(Frame *f, IxpMsg *m, int sym) {
Frame *fp;
Client *c;
Area *a;
@ -556,7 +560,7 @@ select_frame(Frame *f, Message *m, int sym) {
}
char*
select_area(Area *a, Message *m) {
select_area(Area *a, IxpMsg *m) {
Frame *f;
Area *ap;
View *v;

View File

@ -44,7 +44,7 @@ update_rules(Rule **rule, const char *data) {
return;
while((rul = *rule)) {
*rule = rul->next;
regfree(&rul->regex);
free(rul->regex);
free(rul);
}
for(p = data; *p; p++)
@ -73,7 +73,8 @@ update_rules(Rule **rule, const char *data) {
*rule = emallocz(sizeof(Rule));
*v = 0;
trim(value, " \t/");
if(!regcomp(&(*rule)->regex, regex, 0)) {
(*rule)->regex = regcomp(regex);
if((*rule)->regex) {
strncpy((*rule)->value, value, sizeof(rul->value));
rule = &(*rule)->next;
}

View File

@ -1,326 +1,10 @@
/*
* 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 <errno.h>
/* Public Domain --Kris Maglione */
#include <iconv.h>
#include <stdarg.h>
#include <string.h>
#include <util.h>
#include "dat.h"
#include "fns.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;
}
char*
utfecpy(char *to, char *e, char *from)
{
char *end;
if(to >= e)
return to;
end = memccpy(to, from, '\0', e - to);
if(end == nil){
end = e-1;
while(end>to && (*--end&0xC0)==0x80)
;
*end = '\0';
}else{
end--;
}
return end;
}
char*
utfrune(char *s, long c)
{
long c1;
Rune r;
int n;
if(c < Runesync) /* not part of utf sequence */
return strchr(s, c);
for(;;) {
c1 = *(uchar*)s;
if(c1 < Runeself) { /* one byte rune */
if(c1 == 0)
return 0;
if(c1 == c)
return s;
s++;
continue;
}
n = chartorune(&r, s);
if(r == c)
return s;
s += n;
}
}
int
utflen(char *s)
{
int c;
long n;
Rune rune;
n = 0;
for(;;) {
c = *(uchar*)s;
if(c < Runeself) {
if(c == 0)
return n;
s++;
} else
s += chartorune(&rune, s);
n++;
}
}
int
utfnlen(char *s, long m)
{
int c;
long n;
Rune rune;
char *es;
es = s + m;
for(n = 0; s < es; n++) {
c = *(uchar*)s;
if(c < Runeself){
if(c == '\0')
break;
s++;
continue;
}
if(!fullrune(s, es-s))
break;
s += chartorune(&rune, s);
}
return n;
}
char*
utfrrune(char *s, long c)
{
long c1;
Rune r;
char *s1;
if(c < Runesync) /* not part of utf sequence */
return strrchr(s, c);
s1 = 0;
for(;;) {
c1 = *(uchar*)s;
if(c1 < Runeself) { /* one byte rune */
if(c1 == 0)
return s1;
if(c1 == c)
s1 = s;
s++;
continue;
}
c1 = chartorune(&r, s);
if(r == c)
s1 = s;
s += c1;
}
}
/*
* Return pointer to first occurrence of s2 in s1,
* 0 if none
*/
char*
utfutf(char *s1, char *s2)
{
char *p;
long f, n1, n2;
Rune r;
n1 = chartorune(&r, s2);
f = r;
if(f <= Runesync) /* represents self */
return strstr(s1, s2);
n2 = strlen(s2);
for(p=s1; (p=utfrune(p, f)); p+=n1)
if(strncmp(p, s2, n2) == 0)
return p;
return 0;
}
/* This iconv crud is not by Ken or Rob. It is in the Public Domain. */
char*
toutf8n(char *str, size_t nstr) {
static iconv_t cd;
@ -353,48 +37,3 @@ toutf8(char *str) {
return toutf8n(str, strlen(str));
}
/*
* space ranges
*/
static
Rune __space2[] =
{
0x0009, 0x000a, /* tab and newline */
0x0020, 0x0020, /* space */
0x00a0, 0x00a0, /*   */
0x2000, 0x200b, /*   - */
0x2028, 0x2029, /* - */
0x3000, 0x3000, /*   */
0xfeff, 0xfeff, /*  */
};
static Rune*
bsearch(Rune c, Rune *t, int n, int ne)
{
Rune *p;
int m;
while(n > 1) {
m = n/2;
p = t + m*ne;
if(c >= p[0]) {
t = p;
n = n-m;
} else
n = m;
}
if(n && c >= t[0])
return t;
return 0;
}
int
isspacerune(Rune c)
{
Rune *p;
p = bsearch(c, __space2, nelem(__space2)/2, 2);
if(p && c >= p[0] && c <= p[1])
return 1;
return 0;
}

View File

@ -338,26 +338,26 @@ view_index(View *v) {
uint i;
buf = buffer;
end = buffer+sizeof(buffer);
end = buffer+sizeof(buffer)-1;
for((a=v->area), (i=0); a && buf < end-1; (a=a->next), i++) {
if(a->floating)
buf += snprintf(buf, end-buf, "# ~ %d %d\n",
buf = seprint(buf, end, "# ~ %d %d\n",
Dx(a->r), Dy(a->r));
else
buf += snprintf(buf, end-buf, "# %d %d %d\n",
buf = seprint(buf, end, "# %d %d %d\n",
i, a->r.min.x, Dx(a->r));
for(f=a->frame; f && buf < end-1; f=f->anext) {
r = &f->r;
if(a->floating)
buf += snprintf(buf, end-buf, "~ 0x%x %d %d %d %d %s\n",
(uint)f->client->w.w,
buf = seprint(buf, end, "~ %C %d %d %d %d %s\n",
f->client,
r->min.x, r->min.y,
Dx(*r), Dy(*r),
f->client->props);
else
buf += snprintf(buf, end-buf, "%d 0x%x %d %d %s\n",
i, (uint)f->client->w.w,
buf = seprint(buf, end, "%d %C %d %d %s\n",
i, f->client,
r->min.y, Dy(*r),
f->client->props);
}
@ -372,22 +372,22 @@ view_ctl(View *v) {
uint i;
buf = buffer;
end = buffer+sizeof(buffer);
end = buffer+sizeof(buffer)-1;
buf += snprintf(buf, end-buf, "%s\n", v->name);
buf = seprint(buf, end, "%s\n", v->name);
/* select <area>[ <frame>] */
buf += snprintf(buf, end-buf, "select %s", area_name(v->sel));
buf = seprint(buf, end, "select %s", area_name(v->sel));
if(v->sel->sel)
buf += snprintf(buf, end-buf, " %d", frame_idx(v->sel->sel));
buf += snprintf(buf, end-buf, "\n");
buf = seprint(buf, end, " %d", frame_idx(v->sel->sel));
buf = seprint(buf, end, "\n");
/* select client <client> */
if(v->sel->sel)
buf += snprintf(buf, end-buf, "select client 0x%x\n", clientwin(v->sel->sel->client));
buf = seprint(buf, end, "select client %C\n", v->sel->sel->client);
for(a = v->area->next, i = 1; a && buf < end-1; a = a->next, i++) {
buf += snprintf(buf, end-buf, "colmode %d %s\n",
buf = seprint(buf, end, "colmode %d %s\n",
i, colmode2str(a->mode));
}
return (uchar*)buffer;
@ -420,12 +420,11 @@ update_views(void) {
uint
newcolw(View *v, int num) {
regmatch_t regm;
Rule *r;
uint n;
for(r=def.colrules.rule; r; r=r->next)
if(!regexec(&r->regex, v->name, 1, &regm, 0)) {
if(regexec(r->regex, v->name, nil, 0)) {
char buf[sizeof r->value];
char *toks[16];

View File

@ -6,7 +6,9 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#include <bio.h>
#include "dat.h"
#include "fns.h"
@ -94,6 +96,30 @@ rectsubpt(Rectangle r, Point p) {
return r;
}
static int
Rfmt(Fmt *f) {
Rectangle r;
r = va_arg(f->args, Rectangle);
return fmtprint(f, "%P+%dx%d", r.min, Dx(r), Dy(r));
}
static int
Pfmt(Fmt *f) {
Point p;
p = va_arg(f->args, Point);
return fmtprint(f, "(%d,%d)", p.x, p.y);
}
static int
Wfmt(Fmt *f) {
Window *w;
w = va_arg(f->args, Window*);
return fmtprint(f, "0x%ux", w);
}
/* Init */
void
initdisplay(void) {
@ -117,6 +143,10 @@ initdisplay(void) {
wmap.nhash = nelem(wbucket);
amap.bucket = abucket;
amap.nhash = nelem(abucket);
fmtinstall('R', Rfmt);
fmtinstall('P', Pfmt);
fmtinstall('W', Wfmt);
}
/* Images */
@ -139,6 +169,7 @@ freeimage(Image *img) {
XFreePixmap(display, img->image);
XFreeGC(display, img->gc);
free(img);
}
/* Windows */
@ -182,6 +213,7 @@ destroywindow(Window *w) {
if(w->gc)
XFreeGC(display, w->gc);
XDestroyWindow(display, w->w);
free(w);
}
void
@ -371,7 +403,7 @@ drawstring(Image *dst, Font *font,
char *text, ulong col) {
char *buf;
uint x, y, w, h, len;
Bool shortened;
int shortened;
shortened = 0;
@ -463,6 +495,7 @@ loadcolor(CTuple *c, char *str) {
/* Fonts */
Font *
loadfont(char *name) {
Biobuf *b;
Font *f;
XFontStruct **xfonts;
char **missing, **font_names;
@ -473,13 +506,13 @@ loadfont(char *name) {
f->name = estrdup(name);
f->set = XCreateFontSet(display, name, &missing, &n, nil);
if(missing) {
setvbuf(stderr, nil, _IOLBF, 0);
fprintf(stderr, "%s: note: missing fontset%s for '%s':", argv0,
b = Bfdopen(dup(2), O_WRONLY);
Bprint(b, "%s: note: missing fontset%s for '%s':", argv0,
(n > 1 ? "s" : ""), name);
for(i = 0; i < n; i++)
fprintf(stderr, "%s %s", (i ? "," : ""), missing[i]);
fprintf(stderr, "\n");
setvbuf(stderr, nil, _IONBF, 0);
Bprint(b, "%s %s", (i ? "," : ""), missing[i]);
Bprint(b, "\n");
Bterm(b);
freestringlist(missing);
}
@ -491,7 +524,7 @@ loadfont(char *name) {
else {
f->xfont = XLoadQueryFont(display, name);
if(!f->xfont) {
fprintf(stderr, "%s: cannot load font: %s\n", argv0, name);
fprint(2, "%s: cannot load font: %s\n", argv0, name);
freefont(f);
return nil;
}
@ -805,5 +838,5 @@ gravitate(Rectangle rc, Rectangle rf, Point grav) {
d = divpt(d, Pt(2, 2));
d = mulpt(d, grav);
return rectaddpt(rc, d);
return rectsubpt(rc, d);
}

View File

@ -1,6 +1,8 @@
/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com>
* See LICENSE file for license details.
*/
#define IXP_NO_P9_
#define IXP_P9_STRUCTS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -8,6 +10,7 @@
#include <unistd.h>
#include <ixp.h>
#include <util.h>
#include <fmt.h>
static IxpClient *client;
@ -20,17 +23,22 @@ usage(void) {
exit(1);
}
static int
errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf());
}
/* Utility Functions */
static void
write_data(IxpCFid *fid, char *name) {
void *buf;
int len;
buf = ixp_emalloc(fid->iounit);;
buf = emalloc(fid->iounit);;
do {
len = read(0, buf, fid->iounit);
if(len > 0 && ixp_write(fid, buf, len) != len)
fatal("cannot write file '%s': %s\n", name, errstr);
fatal("cannot write file '%s': %r\n", name);
} while(len > 0);
free(buf);
@ -106,7 +114,7 @@ xwrite(int argc, char *argv[]) {
file = EARGF(usage());
fid = ixp_open(client, file, P9_OWRITE);
if(fid == nil)
fatal("Can't open file '%s': %s\n", file, errstr);
fatal("Can't open file '%s': %r\n", file);
write_data(fid, file);
return 0;
@ -126,17 +134,17 @@ xawrite(int argc, char *argv[]) {
file = EARGF(usage());
fid = ixp_open(client, file, P9_OWRITE);
if(fid == nil)
fatal("Can't open file '%s': %s\n", file, errstr);
fatal("Can't open file '%s': %r\n", file);
nbuf = 0;
mbuf = 128;
buf = ixp_emalloc(mbuf);
buf = emalloc(mbuf);
while(argc) {
arg = ARGF();
len = strlen(arg);
if(nbuf + len > mbuf) {
mbuf <<= 1;
buf = ixp_erealloc(buf, mbuf);
buf = erealloc(buf, mbuf);
}
memcpy(buf+nbuf, arg, len);
nbuf += len;
@ -145,7 +153,7 @@ xawrite(int argc, char *argv[]) {
}
if(ixp_write(fid, buf, nbuf) == -1)
fatal("cannot write file '%s': %s\n", file, errstr);
fatal("cannot write file '%s': %r\n", file);
return 0;
}
@ -162,7 +170,7 @@ xcreate(int argc, char *argv[]) {
file = EARGF(usage());
fid = ixp_create(client, file, 0777, P9_OWRITE);
if(fid == nil)
fatal("Can't create file '%s': %s\n", file, errstr);
fatal("Can't create file '%s': %r\n", file);
if((fid->qid.type&P9_DMDIR) == 0)
write_data(fid, file);
@ -181,7 +189,7 @@ xremove(int argc, char *argv[]) {
file = EARGF(usage());
if(ixp_remove(client, file) == 0)
fatal("Can't remove file '%s': %s\n", file, errstr);
fatal("Can't remove file '%s': %r\n", file);
return 0;
}
@ -199,21 +207,21 @@ xread(int argc, char *argv[]) {
file = EARGF(usage());
fid = ixp_open(client, file, P9_OREAD);
if(fid == nil)
fatal("Can't open file '%s': %s\n", file, errstr);
fatal("Can't open file '%s': %r\n", file);
buf = ixp_emalloc(fid->iounit);
buf = emalloc(fid->iounit);
while((count = ixp_read(fid, buf, fid->iounit)) > 0)
write(1, buf, count);
if(count == -1)
fatal("cannot read file/directory '%s': %s\n", file, errstr);
fatal("cannot read file/directory '%s': %r\n", file);
return 0;
}
static int
xls(int argc, char *argv[]) {
Message m;
IxpMsg m;
Stat *stat;
IxpCFid *fid;
char *file;
@ -237,7 +245,7 @@ xls(int argc, char *argv[]) {
stat = ixp_stat(client, file);
if(stat == nil)
fatal("cannot stat file '%s': %s\n", file, errstr);
fatal("cannot stat file '%s': %r\n", file);
if(dflag || (stat->mode&P9_DMDIR) == 0) {
print_stat(stat, lflag);
@ -248,12 +256,12 @@ xls(int argc, char *argv[]) {
fid = ixp_open(client, file, P9_OREAD);
if(fid == nil)
fatal("Can't open file '%s': %s\n", file, errstr);
fatal("Can't open file '%s': %r\n", file);
nstat = 0;
mstat = 16;
stat = ixp_emalloc(sizeof(*stat) * mstat);
buf = ixp_emalloc(fid->iounit);
stat = emalloc(sizeof(*stat) * mstat);
buf = emalloc(fid->iounit);
while((count = ixp_read(fid, buf, fid->iounit)) > 0) {
m = ixp_message(buf, count, MsgUnpack);
while(m.pos < m.end) {
@ -273,7 +281,7 @@ xls(int argc, char *argv[]) {
free(stat);
if(count == -1)
fatal("cannot read directory '%s': %s\n", file, errstr);
fatal("cannot read directory '%s': %r\n", file);
return 0;
}
@ -298,6 +306,8 @@ main(int argc, char *argv[]) {
exectab *tab;
int ret;
fmtinstall('r', errfmt);
address = getenv("WMII_ADDRESS");
ARGBEGIN{
@ -318,7 +328,7 @@ main(int argc, char *argv[]) {
client = ixp_mount(address);
if(client == nil)
fatal("%s\n", errstr);
fatal("can't mount: %r\n");
for(tab = etab; tab->cmd; tab++)
if(strcmp(cmd, tab->cmd) == 0) break;

View File

@ -10,7 +10,7 @@ INCLUDE = ${PREFIX}/include
# Includes and libs
INCPATH = .:${ROOT}/include:${INCLUDE}:/usr/include
LIBS = -L/usr/lib -lc
LIBS = -L/usr/lib -lc -L${ROOT}/lib
# Flags
include ${ROOT}/mk/gcc.mk
@ -23,6 +23,8 @@ MKDEP = cpp -M
CC = cc -c
# Linker (Under normal circumstances, this should *not* be 'ld')
LD = cc
# Archiver
AR = ar crs
AWKPATH = $$(which awk)
P9PATHS = ${PLAN9}:"'$${HOME}/plan9'":/usr/local/plan9:/usr/local/9:/opt/plan9:/opt/9:/usr/plan9:/usr/9

BIN
img/wmii.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

87
include/bio.h Normal file
View File

@ -0,0 +1,87 @@
#ifndef _BIO_H_
#define _BIO_H_ 1
#ifdef AUTOLIB
AUTOLIB(bio)
#endif
#include <sys/types.h> /* for off_t */
#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
#include <stdarg.h> /* for va_list */
typedef struct Biobuf Biobuf;
enum
{
Bsize = 8*1024,
Bungetsize = 4, /* space for ungetc */
Bmagic = 0x314159,
Beof = -1,
Bbad = -2,
Binactive = 0, /* states */
Bractive,
Bwactive,
Bracteof,
Bend
};
struct Biobuf
{
int icount; /* neg num of bytes at eob */
int ocount; /* num of bytes at bob */
int rdline; /* num of bytes after rdline */
int runesize; /* num of bytes of last getrune */
int state; /* r/w/inactive */
int fid; /* open file */
int flag; /* magic if malloc'ed */
off_t offset; /* offset of buffer in file */
int bsize; /* size of buffer */
unsigned char* bbuf; /* pointer to beginning of buffer */
unsigned char* ebuf; /* pointer to end of buffer */
unsigned char* gbuf; /* pointer to good data in buf */
unsigned char b[Bungetsize+Bsize];
};
#define BGETC(bp)\
((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
#define BPUTC(bp,c)\
((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
#define BOFFSET(bp)\
(((bp)->state==Bractive)?\
(bp)->offset + (bp)->icount:\
(((bp)->state==Bwactive)?\
(bp)->offset + ((bp)->bsize + (bp)->ocount):\
-1))
#define BLINELEN(bp)\
(bp)->rdline
#define BFILDES(bp)\
(bp)->fid
int Bbuffered(Biobuf*);
Biobuf* Bfdopen(int, int);
int Bfildes(Biobuf*);
int Bflush(Biobuf*);
int Bgetc(Biobuf*);
int Bgetd(Biobuf*, double*);
long Bgetrune(Biobuf*);
int Binit(Biobuf*, int, int);
int Binits(Biobuf*, int, int, unsigned char*, int);
int Blinelen(Biobuf*);
off_t Boffset(Biobuf*);
Biobuf* Bopen(char*, int);
int Bprint(Biobuf*, char*, ...);
int Bputc(Biobuf*, int);
int Bputrune(Biobuf*, long);
void* Brdline(Biobuf*, int);
char* Brdstr(Biobuf*, int, int);
long Bread(Biobuf*, void*, long);
off_t Bseek(Biobuf*, off_t, int);
int Bterm(Biobuf*);
int Bungetc(Biobuf*);
int Bungetrune(Biobuf*);
long Bwrite(Biobuf*, void*, long);
int Bvprint(Biobuf*, char*, va_list);
#endif

95
include/fmt.h Normal file
View File

@ -0,0 +1,95 @@
#ifndef _FMT_H_
#define _FMT_H_ 1
/*
* 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>
typedef struct Fmt Fmt;
struct Fmt{
unsigned char runes; /* output buffer is runes or chars? */
void *start; /* of buffer */
void *to; /* current place in the buffer */
void *stop; /* end of the buffer; overwritten if flush fails */
int (*flush)(Fmt *); /* called when to == stop */
void *farg; /* to make flush a closure */
int nfmt; /* num chars formatted so far */
va_list args; /* args passed to dofmt */
int r; /* % format Rune */
int width;
int prec;
unsigned long flags;
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtZero = FmtSign << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtByte = FmtComma << 1,
FmtLDouble = FmtByte << 1,
FmtFlag = FmtLDouble << 1
};
extern int (*fmtdoquote)(int);
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
int dofmt(Fmt *f, char *fmt);
int dorfmt(Fmt *f, const Rune *fmt);
double fmtcharstod(int(*f)(void*), void *vp);
int fmtfdflush(Fmt *f);
int fmtfdinit(Fmt *f, int fd, char *buf, int size);
int fmtinstall(int c, int (*f)(Fmt*));
int fmtprint(Fmt *f, char *fmt, ...);
int fmtrune(Fmt *f, int r);
int fmtrunestrcpy(Fmt *f, Rune *s);
int fmtstrcpy(Fmt *f, char *s);
char* fmtstrflush(Fmt *f);
int fmtstrinit(Fmt *f);
double fmtstrtod(const char *as, char **aas);
int fmtvprint(Fmt *f, char *fmt, va_list args);
int fprint(int fd, char *fmt, ...);
int print(char *fmt, ...);
void quotefmtinstall(void);
int quoterunestrfmt(Fmt *f);
int quotestrfmt(Fmt *f);
Rune* runefmtstrflush(Fmt *f);
int runefmtstrinit(Fmt *f);
Rune* runeseprint(Rune *buf, Rune *e, char *fmt, ...);
Rune* runesmprint(char *fmt, ...);
int runesnprint(Rune *buf, int len, char *fmt, ...);
int runesprint(Rune *buf, char *fmt, ...);
Rune* runevseprint(Rune *buf, Rune *e, char *fmt, va_list args);
Rune* runevsmprint(char *fmt, va_list args);
int runevsnprint(Rune *buf, int len, char *fmt, va_list args);
char* seprint(char *buf, char *e, char *fmt, ...);
char* smprint(char *fmt, ...);
int snprint(char *buf, int len, char *fmt, ...);
int sprint(char *buf, char *fmt, ...);
int vfprint(int fd, char *fmt, va_list args);
char* vseprint(char *buf, char *e, char *fmt, va_list args);
char* vsmprint(char *fmt, va_list args);
int vsnprint(char *buf, int len, char *fmt, va_list args);
#endif

41
include/plan9.h Normal file
View File

@ -0,0 +1,41 @@
/*
* compiler directive on Plan 9
*/
#ifndef USED
#define USED(x) if(x);else
#endif
#include <utf.h>
#include <fmt.h>
#include <string.h>
#include <unistd.h>
/*
* easiest way to make sure these are defined
*/
#define uchar _p9uchar
#define ushort _p9ushort
#define uint _p9uint
#define ulong _p9ulong
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef long long vlong;
typedef unsigned long long uvlong;
#define OREAD O_RDONLY
#define OWRITE O_WRONLY
#define OCEXEC 0
#define ORCLOSE 0
#define OTRUNC 0
#define exits(x) exit(x && *x ? 1 : 0)
#undef nil
#define nil ((void*)0)
#undef nelem
#define nelem(x) (sizeof (x)/sizeof (x)[0])

71
include/regcomp.h Normal file
View File

@ -0,0 +1,71 @@
/*
* substitution list
*/
#define NSUBEXP 32
typedef struct Resublist Resublist;
struct Resublist
{
Resub m[NSUBEXP];
};
/* max character classes per program */
extern Reprog RePrOg;
#define NCLASS (sizeof(RePrOg.class)/sizeof(Reclass))
/* max rune ranges per character class */
#define NCCRUNE (sizeof(Reclass)/sizeof(Rune))
/*
* Actions and Tokens (Reinst types)
*
* 02xx are operators, value == precedence
* 03xx are tokens, i.e. operands for operators
*/
#define RUNE 0177
#define OPERATOR 0200 /* Bitmask of all operators */
#define START 0200 /* Start, used for marker on stack */
#define RBRA 0201 /* Right bracket, ) */
#define LBRA 0202 /* Left bracket, ( */
#define OR 0203 /* Alternation, | */
#define CAT 0204 /* Concatentation, implicit operator */
#define STAR 0205 /* Closure, * */
#define PLUS 0206 /* a+ == aa* */
#define QUEST 0207 /* a? == a|nothing, i.e. 0 or 1 a's */
#define ANY 0300 /* Any character except newline, . */
#define ANYNL 0301 /* Any character including newline, . */
#define NOP 0302 /* No operation, internal use only */
#define BOL 0303 /* Beginning of line, ^ */
#define EOL 0304 /* End of line, $ */
#define CCLASS 0305 /* Character class, [] */
#define NCCLASS 0306 /* Negated character class, [] */
#define END 0377 /* Terminate: match found */
/*
* regexec execution lists
*/
#define LISTSIZE 10
#define BIGLISTSIZE (10*LISTSIZE)
typedef struct Relist Relist;
struct Relist
{
Reinst* inst; /* Reinstruction of the thread */
Resublist se; /* matched subexpressions in this thread */
};
typedef struct Reljunk Reljunk;
struct Reljunk
{
Relist* relist[2];
Relist* reliste[2];
int starttype;
Rune startchar;
char* starts;
char* eol;
Rune* rstarts;
Rune* reol;
};
extern Relist* _renewthread(Relist*, Reinst*, int, Resublist*);
extern void _renewmatch(Resub*, int, Resublist*);
extern Relist* _renewemptythread(Relist*, Reinst*, int, char*);
extern Relist* _rrenewemptythread(Relist*, Reinst*, int, Rune*);

90
include/regexp9.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef _REGEXP9_H_
#define _REGEXP9_H_ 1
#ifdef AUTOLIB
AUTOLIB(regexp9)
#endif
#include <utf.h>
typedef struct Resub Resub;
typedef struct Reclass Reclass;
typedef struct Reinst Reinst;
typedef struct Reprog Reprog;
/*
* Sub expression matches
*/
struct Resub{
union
{
char *sp;
Rune *rsp;
}s;
union
{
char *ep;
Rune *rep;
}e;
};
/*
* character class, each pair of rune's defines a range
*/
struct Reclass{
Rune *end;
Rune spans[64];
};
/*
* Machine instructions
*/
struct Reinst{
int type;
union {
Reclass *cp; /* class pointer */
Rune r; /* character */
int subid; /* sub-expression id for RBRA and LBRA */
Reinst *right; /* right child of OR */
}u1;
union { /* regexp relies on these two being in the same union */
Reinst *left; /* left child of OR */
Reinst *next; /* next instruction for CAT & LBRA */
}u2;
};
/*
* Reprogram definition
*/
struct Reprog{
Reinst *startinst; /* start pc */
Reclass class[32]; /* .data */
Reinst firstinst[5]; /* .text */
};
extern Reprog *regcomp9(char*);
extern Reprog *regcomplit9(char*);
extern Reprog *regcompnl9(char*);
extern void regerror9(char*);
extern int regexec9(Reprog*, char*, Resub*, int);
extern void regsub9(char*, char*, int, Resub*, int);
extern int rregexec9(Reprog*, Rune*, Resub*, int);
extern void rregsub9(Rune*, Rune*, int, Resub*, int);
/*
* Darwin simply cannot handle having routines that
* override other library routines.
*/
#ifndef NOPLAN9DEFINES
#define regcomp regcomp9
#define regcomplit regcomplit9
#define regcompnl regcompnl9
#define regerror regerror9
#define regexec regexec9
#define regsub regsub9
#define rregexec rregexec9
#define rregsub rregsub9
#endif
#endif

47
include/utf.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef _UTF_H_
#define _UTF_H_ 1
typedef unsigned short Rune; /* 16 bits */
enum
{
UTFmax = 3, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
Runeerror = 0xFFFD, /* decoding error in UTF */
};
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
int chartorune(Rune *rune, char *str);
int fullrune(char *str, int n);
int isalpharune(Rune c);
int islowerrune(Rune c);
int isspacerune(Rune c);
int istitlerune(Rune c);
int isupperrune(Rune c);
int runelen(long c);
int runenlen(Rune *r, int nrune);
Rune* runestrcat(Rune *s1, Rune *s2);
Rune* runestrchr(Rune *s, Rune c);
int runestrcmp(Rune *s1, Rune *s2);
Rune* runestrcpy(Rune *s1, Rune *s2);
Rune* runestrdup(Rune *s) ;
Rune* runestrecpy(Rune *s1, Rune *es1, Rune *s2);
long runestrlen(Rune *s);
Rune* runestrncat(Rune *s1, Rune *s2, long n);
int runestrncmp(Rune *s1, Rune *s2, long n);
Rune* runestrncpy(Rune *s1, Rune *s2, long n);
Rune* runestrrchr(Rune *s, Rune c);
Rune* runestrstr(Rune *s1, Rune *s2);
int runetochar(char *str, Rune *rune);
Rune tolowerrune(Rune c);
Rune totitlerune(Rune c);
Rune toupperrune(Rune c);
char* utfecpy(char *to, char *e, char *from);
int utflen(char *s);
int utfnlen(char *s, long m);
char* utfrrune(char *s, long c);
char* utfrune(char *s, long c);
char* utfutf(char *s1, char *s2);
#endif

27
libbio/Makefile Normal file
View File

@ -0,0 +1,27 @@
ROOT= ..
include ${ROOT}/mk/hdr.mk
VERSION=2.0
TARG=libbio
OBJ=\
bbuffered\
bfildes\
bflush\
bgetc\
bgetd\
bgetrune\
binit\
boffset\
bprint\
bvprint\
bputc\
bputrune\
brdline\
brdstr\
bread\
bseek\
bwrite
include ${ROOT}/mk/lib.mk

34
libbio/NOTICE Normal file
View File

@ -0,0 +1,34 @@
This copyright NOTICE applies to all files in this directory and
subdirectories, unless another copyright notice appears in a given
file or subdirectory. If you take substantial code from this software to use in
other programs, you must somehow include with it an appropriate
copyright notice that includes the copyright notice and the other
notices below. It is fine (and often tidier) to do that in a separate
file such as NOTICE, LICENCE or COPYING.
Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
Revisions Copyright © 2000-2005 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
----
This software is also made available under the Lucent Public License
version 1.02; see http://plan9.bell-labs.com/plan9dist/license.html

5
libbio/README Normal file
View File

@ -0,0 +1,5 @@
This software was packaged for Unix by Russ Cox.
Please send comments to rsc@swtch.com.
http://swtch.com/plan9port/unix

20
libbio/bbuffered.c Normal file
View File

@ -0,0 +1,20 @@
#include "plan9.h"
#include <bio.h>
int
Bbuffered(Biobuf *bp)
{
switch(bp->state) {
case Bracteof:
case Bractive:
return -bp->icount;
case Bwactive:
return bp->bsize + bp->ocount;
case Binactive:
return 0;
}
fprint(2, "Bbuffered: unknown state %d\n", bp->state);
return 0;
}

46
libbio/bcat.c Normal file
View File

@ -0,0 +1,46 @@
#include <fmt.h>
#include "bio.h"
Biobuf bout;
void
bcat(Biobuf *b, char *name)
{
char buf[1000];
int n;
while((n = Bread(b, buf, sizeof buf)) > 0){
if(Bwrite(&bout, buf, n) < 0)
fprint(2, "writing during %s: %r\n", name);
}
if(n < 0)
fprint(2, "reading %s: %r\n", name);
}
int
main(int argc, char **argv)
{
int i;
Biobuf b, *bp;
Fmt fmt;
Binit(&bout, 1, O_WRONLY);
Bfmtinit(&fmt, &bout);
fmtprint(&fmt, "hello, world\n");
Bfmtflush(&fmt);
if(argc == 1){
Binit(&b, 0, O_RDONLY);
bcat(&b, "<stdin>");
}else{
for(i=1; i<argc; i++){
if((bp = Bopen(argv[i], O_RDONLY)) == 0){
fprint(2, "Bopen %s: %r\n", argv[i]);
continue;
}
bcat(bp, argv[i]);
Bterm(bp);
}
}
exit(0);
}

9
libbio/bfildes.c Normal file
View File

@ -0,0 +1,9 @@
#include "plan9.h"
#include <bio.h>
int
Bfildes(Biobuf *bp)
{
return bp->fid;
}

33
libbio/bflush.c Normal file
View File

@ -0,0 +1,33 @@
#include "plan9.h"
#include <bio.h>
int
Bflush(Biobuf *bp)
{
int n, c;
switch(bp->state) {
case Bwactive:
n = bp->bsize+bp->ocount;
if(n == 0)
return 0;
c = write(bp->fid, bp->bbuf, n);
if(n == c) {
bp->offset += n;
bp->ocount = -bp->bsize;
return 0;
}
bp->state = Binactive;
bp->ocount = 0;
break;
case Bracteof:
bp->state = Bractive;
case Bractive:
bp->icount = 0;
bp->gbuf = bp->ebuf;
return 0;
}
return Beof;
}

53
libbio/bgetc.c Normal file
View File

@ -0,0 +1,53 @@
#include "plan9.h"
#include <bio.h>
int
Bgetc(Biobuf *bp)
{
int i;
loop:
i = bp->icount;
if(i != 0) {
bp->icount = i+1;
return bp->ebuf[i];
}
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
return Beof;
}
/*
* get next buffer, try to keep Bungetsize
* characters pre-catenated from the previous
* buffer to allow that many ungets.
*/
memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
i = read(bp->fid, bp->bbuf, bp->bsize);
bp->gbuf = bp->bbuf;
if(i <= 0) {
bp->state = Bracteof;
if(i < 0)
bp->state = Binactive;
return Beof;
}
if(i < bp->bsize) {
memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
bp->gbuf = bp->ebuf-i;
}
bp->icount = -i;
bp->offset += i;
goto loop;
}
int
Bungetc(Biobuf *bp)
{
if(bp->state == Bracteof)
bp->state = Bractive;
if(bp->state != Bractive)
return Beof;
bp->icount--;
return 1;
}

36
libbio/bgetd.c Normal file
View File

@ -0,0 +1,36 @@
#include "plan9.h"
#include <bio.h>
struct bgetd
{
Biobuf* b;
int eof;
};
static int
Bgetdf(void *vp)
{
int c;
struct bgetd *bg = vp;
c = Bgetc(bg->b);
if(c == Beof)
bg->eof = 1;
return c;
}
int
Bgetd(Biobuf *bp, double *dp)
{
double d;
struct bgetd b;
b.b = bp;
b.eof = 0;
d = fmtcharstod(Bgetdf, &b);
if(b.eof)
return -1;
Bungetc(bp);
*dp = d;
return 1;
}

47
libbio/bgetrune.c Normal file
View File

@ -0,0 +1,47 @@
#include "plan9.h"
#include <bio.h>
#include <utf.h>
long
Bgetrune(Biobuf *bp)
{
int c, i;
Rune rune;
char str[4];
c = Bgetc(bp);
if(c < Runeself) { /* one char */
bp->runesize = 1;
return c;
}
str[0] = c;
for(i=1;;) {
c = Bgetc(bp);
if(c < 0)
return c;
str[i++] = c;
if(fullrune(str, i)) {
bp->runesize = chartorune(&rune, str);
while(i > bp->runesize) {
Bungetc(bp);
i--;
}
return rune;
}
}
}
int
Bungetrune(Biobuf *bp)
{
if(bp->state == Bracteof)
bp->state = Bractive;
if(bp->state != Bractive)
return Beof;
bp->icount -= bp->runesize;
bp->runesize = 0;
return 1;
}

154
libbio/binit.c Normal file
View File

@ -0,0 +1,154 @@
#include <stdlib.h>
#include <plan9.h>
#include <bio.h>
enum
{
MAXBUFS = 20
};
static Biobuf* wbufs[MAXBUFS];
static int atexitflag;
static
void
batexit(void)
{
Biobuf *bp;
int i;
for(i=0; i<MAXBUFS; i++) {
bp = wbufs[i];
if(bp != 0) {
wbufs[i] = 0;
Bflush(bp);
}
}
}
static
void
deinstall(Biobuf *bp)
{
int i;
for(i=0; i<MAXBUFS; i++)
if(wbufs[i] == bp)
wbufs[i] = 0;
}
static
void
install(Biobuf *bp)
{
int i;
deinstall(bp);
for(i=0; i<MAXBUFS; i++)
if(wbufs[i] == 0) {
wbufs[i] = bp;
break;
}
if(atexitflag == 0) {
atexitflag = 1;
atexit(batexit);
}
}
int
Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
{
p += Bungetsize; /* make room for Bungets */
size -= Bungetsize;
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return Beof;
case OREAD:
bp->state = Bractive;
bp->ocount = 0;
break;
case OWRITE:
install(bp);
bp->state = Bwactive;
bp->ocount = -size;
break;
}
bp->bbuf = p;
bp->ebuf = p+size;
bp->bsize = size;
bp->icount = 0;
bp->gbuf = bp->ebuf;
bp->fid = f;
bp->flag = 0;
bp->rdline = 0;
bp->offset = 0;
bp->runesize = 0;
return 0;
}
int
Binit(Biobuf *bp, int f, int mode)
{
return Binits(bp, f, mode, bp->b, sizeof(bp->b));
}
Biobuf*
Bfdopen(int f, int mode)
{
Biobuf *bp;
bp = malloc(sizeof(Biobuf));
if(bp == 0)
return 0;
Binits(bp, f, mode, bp->b, sizeof(bp->b));
bp->flag = Bmagic;
return bp;
}
Biobuf*
Bopen(char *name, int mode)
{
Biobuf *bp;
int f;
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return 0;
case OREAD:
f = open(name, OREAD);
if(f < 0)
return 0;
break;
case OWRITE:
f = creat(name, 0666);
if(f < 0)
return 0;
}
bp = Bfdopen(f, mode);
if(bp == 0)
close(f);
return bp;
}
int
Bterm(Biobuf *bp)
{
deinstall(bp);
Bflush(bp);
if(bp->flag == Bmagic) {
bp->flag = 0;
close(bp->fid);
free(bp);
}
return 0;
}

371
libbio/bio.3 Normal file
View File

@ -0,0 +1,371 @@
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.TH BIO 3
.SH NAME
Bopen, Bfdopen, Binit, Binits, Brdline, Brdstr, Bgetc, Bgetrune, Bgetd, Bungetc, Bungetrune, Bread, Bseek, Boffset, Bfildes, Blinelen, Bputc, Bputrune, Bprint, Bvprint, Bwrite, Bflush, Bterm, Bbuffered \- buffered input/output
.SH SYNOPSIS
.ta \w'\fLBiobuf* 'u
.B #include <utf.h>
.br
.B #include <fmt.h>
.br
.B #include <bio.h>
.PP
.B
Biobuf* Bopen(char *file, int mode)
.PP
.B
Biobuf* Bfdopen(int fd, int mode)
.PP
.B
int Binit(Biobuf *bp, int fd, int mode)
.PP
.B
int Binits(Biobufhdr *bp, int fd, int mode, uchar *buf, int size)
.PP
.B
int Bterm(Biobufhdr *bp)
.PP
.B
int Bprint(Biobufhdr *bp, char *format, ...)
.PP
.B
int Bvprint(Biobufhdr *bp, char *format, va_list arglist);
.PP
.B
void* Brdline(Biobufhdr *bp, int delim)
.PP
.B
char* Brdstr(Biobufhdr *bp, int delim, int nulldelim)
.PP
.B
int Blinelen(Biobufhdr *bp)
.PP
.B
vlong Boffset(Biobufhdr *bp)
.PP
.B
int Bfildes(Biobufhdr *bp)
.PP
.B
int Bgetc(Biobufhdr *bp)
.PP
.B
long Bgetrune(Biobufhdr *bp)
.PP
.B
int Bgetd(Biobufhdr *bp, double *d)
.PP
.B
int Bungetc(Biobufhdr *bp)
.PP
.B
int Bungetrune(Biobufhdr *bp)
.PP
.B
vlong Bseek(Biobufhdr *bp, vlong n, int type)
.PP
.B
int Bputc(Biobufhdr *bp, int c)
.PP
.B
int Bputrune(Biobufhdr *bp, long c)
.PP
.B
long Bread(Biobufhdr *bp, void *addr, long nbytes)
.PP
.B
long Bwrite(Biobufhdr *bp, void *addr, long nbytes)
.PP
.B
int Bflush(Biobufhdr *bp)
.PP
.B
int Bbuffered(Biobufhdr *bp)
.PP
.SH DESCRIPTION
These routines implement fast buffered I/O.
I/O on different file descriptors is independent.
.PP
.I Bopen
opens
.I file
for mode
.B O_RDONLY
or creates for mode
.BR O_WRONLY .
It calls
.IR malloc (3)
to allocate a buffer.
.PP
.I Bfdopen
allocates a buffer for the already-open file descriptor
.I fd
for mode
.B O_RDONLY
or
.BR O_WRONLY .
It calls
.IR malloc (3)
to allocate a buffer.
.PP
.I Binit
initializes a standard size buffer, type
.IR Biobuf ,
with the open file descriptor passed in
by the user.
.I Binits
initializes a non-standard size buffer, type
.IR Biobufhdr ,
with the open file descriptor,
buffer area, and buffer size passed in
by the user.
.I Biobuf
and
.I Biobufhdr
are related by the declaration:
.IP
.EX
typedef struct Biobuf Biobuf;
struct Biobuf
{
Biobufhdr;
uchar b[Bungetsize+Bsize];
};
.EE
.PP
Arguments
of types pointer to Biobuf and pointer to Biobufhdr
can be used interchangeably in the following routines.
.PP
.IR Bopen ,
.IR Binit ,
or
.I Binits
should be called before any of the
other routines on that buffer.
.I Bfildes
returns the integer file descriptor of the associated open file.
.PP
.I Bterm
flushes the buffer for
.IR bp .
If the buffer was allocated by
.IR Bopen ,
the buffer is
.I freed
and the file is closed.
.PP
.I Brdline
reads a string from the file associated with
.I bp
up to and including the first
.I delim
character.
The delimiter character at the end of the line is
not altered.
.I Brdline
returns a pointer to the start of the line or
.L 0
on end-of-file or read error.
.I Blinelen
returns the length (including the delimiter)
of the most recent string returned by
.IR Brdline .
.PP
.I Brdstr
returns a
.IR malloc (3)-allocated
buffer containing the next line of input delimited by
.IR delim ,
terminated by a NUL (0) byte.
Unlike
.IR Brdline ,
which returns when its buffer is full even if no delimiter has been found,
.I Brdstr
will return an arbitrarily long line in a single call.
If
.I nulldelim
is set, the terminal delimiter will be overwritten with a NUL.
After a successful call to
.IR Brdstr ,
the return value of
.I Blinelen
will be the length of the returned buffer, excluding the NUL.
.PP
.I Bgetc
returns the next character from
.IR bp ,
or a negative value
at end of file.
.I Bungetc
may be called immediately after
.I Bgetc
to allow the same character to be reread.
.PP
.I Bgetrune
calls
.I Bgetc
to read the bytes of the next
.SM UTF
sequence in the input stream and returns the value of the rune
represented by the sequence.
It returns a negative value
at end of file.
.I Bungetrune
may be called immediately after
.I Bgetrune
to allow the same
.SM UTF
sequence to be reread as either bytes or a rune.
.I Bungetc
and
.I Bungetrune
may back up a maximum of five bytes.
.PP
.I Bgetd
uses
.I fmtcharstod
(see
.IR fmtstrtod (3))
and
.I Bgetc
to read the formatted
floating-point number in the input stream,
skipping initial blanks and tabs.
The value is stored in
.BR *d.
.PP
.I Bread
reads
.I nbytes
of data from
.I bp
into memory starting at
.IR addr .
The number of bytes read is returned on success
and a negative value is returned if a read error occurred.
.PP
.I Bseek
applies
.IR lseek (2)
to
.IR bp .
It returns the new file offset.
.I Boffset
returns the file offset of the next character to be processed.
.PP
.I Bputc
outputs the low order 8 bits of
.I c
on
.IR bp .
If this causes a
.IR write
to occur and there is an error,
a negative value is returned.
Otherwise, a zero is returned.
.PP
.I Bputrune
calls
.I Bputc
to output the low order
16 bits of
.I c
as a rune
in
.SM UTF
format
on the output stream.
.PP
.I Bprint
is a buffered interface to
.IR print (3).
If this causes a
.IR write
to occur and there is an error,
a negative value
.RB ( Beof )
is returned.
Otherwise, the number of bytes output is returned.
.I Bvprint
does the same except it takes as argument a
.B va_list
parameter, so it can be called within a variadic function.
.PP
.I Bwrite
outputs
.I nbytes
of data starting at
.I addr
to
.IR bp .
If this causes a
.IR write
to occur and there is an error,
a negative value is returned.
Otherwise, the number of bytes written is returned.
.PP
.I Bflush
causes any buffered output associated with
.I bp
to be written.
The return is as for
.IR Bputc .
.I Bflush
is called on
exit for every buffer still open
for writing.
.PP
.I Bbuffered
returns the number of bytes in the buffer.
When reading, this is the number of bytes still available from the last
read on the file; when writing, it is the number of bytes ready to be
written.
.SH SOURCE
.B http://swtch.com/plan9port/unix
.SH SEE ALSO
.IR open (2),
.IR print (3),
.IR atexit (3),
.IR utf (7),
.SH DIAGNOSTICS
.I Bio
routines that return integers yield
.B Beof
if
.I bp
is not the descriptor of an open file.
.I Bopen
returns zero if the file cannot be opened in the given mode.
All routines set
.I errstr
on error.
.SH BUGS
.I Brdline
returns an error on strings longer than the buffer associated
with the file
and also if the end-of-file is encountered
before a delimiter.
.I Blinelen
will tell how many characters are available
in these cases.
In the case of a true end-of-file,
.I Blinelen
will return zero.
At the cost of allocating a buffer,
.I Brdstr
sidesteps these issues.
.PP
The data returned by
.I Brdline
may be overwritten by calls to any other
.I bio
routine on the same
.IR bp.

25
libbio/boffset.c Normal file
View File

@ -0,0 +1,25 @@
#include "plan9.h"
#include <bio.h>
off_t
Boffset(Biobuf *bp)
{
off_t n;
switch(bp->state) {
default:
fprint(2, "Boffset: unknown state %d\n", bp->state);
n = Beof;
break;
case Bracteof:
case Bractive:
n = bp->offset + bp->icount;
break;
case Bwactive:
n = bp->offset + (bp->bsize + bp->ocount);
break;
}
return n;
}

14
libbio/bprint.c Normal file
View File

@ -0,0 +1,14 @@
#include "plan9.h"
#include <bio.h>
int
Bprint(Biobuf *bp, char *fmt, ...)
{
int n;
va_list arg;
va_start(arg, fmt);
n = Bvprint(bp, fmt, arg);
va_end(arg);
return n;
}

20
libbio/bputc.c Normal file
View File

@ -0,0 +1,20 @@
#include "plan9.h"
#include <bio.h>
int
Bputc(Biobuf *bp, int c)
{
int i;
for(;;) {
i = bp->ocount;
if(i) {
bp->ebuf[i++] = c;
bp->ocount = i;
return 0;
}
if(Bflush(bp) == Beof)
break;
}
return Beof;
}

23
libbio/bputrune.c Normal file
View File

@ -0,0 +1,23 @@
#include "plan9.h"
#include <bio.h>
#include <utf.h>
int
Bputrune(Biobuf *bp, long c)
{
Rune rune;
char str[4];
int n;
rune = c;
if(rune < Runeself) {
Bputc(bp, rune);
return 1;
}
n = runetochar(str, &rune);
if(n == 0)
return Bbad;
if(Bwrite(bp, str, n) != n)
return Beof;
return n;
}

94
libbio/brdline.c Normal file
View File

@ -0,0 +1,94 @@
#include "plan9.h"
#include <bio.h>
void*
Brdline(Biobuf *bp, int delim)
{
char *ip, *ep;
int i, j;
i = -bp->icount;
if(i == 0) {
/*
* eof or other error
*/
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
bp->rdline = 0;
bp->gbuf = bp->ebuf;
return 0;
}
}
/*
* first try in remainder of buffer (gbuf doesn't change)
*/
ip = (char*)bp->ebuf - i;
ep = memchr(ip, delim, i);
if(ep) {
j = (ep - ip) + 1;
bp->rdline = j;
bp->icount += j;
return ip;
}
/*
* copy data to beginning of buffer
*/
if(i < bp->bsize)
memmove(bp->bbuf, ip, i);
bp->gbuf = bp->bbuf;
/*
* append to buffer looking for the delim
*/
ip = (char*)bp->bbuf + i;
while(i < bp->bsize) {
j = read(bp->fid, ip, bp->bsize-i);
if(j <= 0) {
/*
* end of file with no delim
*/
memmove(bp->ebuf-i, bp->bbuf, i);
bp->rdline = i;
bp->icount = -i;
bp->gbuf = bp->ebuf-i;
return 0;
}
bp->offset += j;
i += j;
ep = memchr(ip, delim, j);
if(ep) {
/*
* found in new piece
* copy back up and reset everything
*/
ip = (char*)bp->ebuf - i;
if(i < bp->bsize){
memmove(ip, bp->bbuf, i);
bp->gbuf = (unsigned char*)ip;
}
j = (ep - (char*)bp->bbuf) + 1;
bp->rdline = j;
bp->icount = j - i;
return ip;
}
ip += j;
}
/*
* full buffer without finding
*/
bp->rdline = bp->bsize;
bp->icount = -bp->bsize;
bp->gbuf = bp->bbuf;
return 0;
}
int
Blinelen(Biobuf *bp)
{
return bp->rdline;
}

112
libbio/brdstr.c Normal file
View File

@ -0,0 +1,112 @@
#include <stdlib.h>
#include <plan9.h>
#include <bio.h>
static char*
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
{
int n;
n = *np;
p = realloc(p, n+ndata+1);
if(p){
memmove(p+n, data, ndata);
n += ndata;
if(n>0 && nulldelim && p[n-1]==delim)
p[--n] = '\0';
else
p[n] = '\0';
*np = n;
}
return p;
}
char*
Brdstr(Biobuf *bp, int delim, int nulldelim)
{
char *ip, *ep, *p;
int i, j;
i = -bp->icount;
bp->rdline = 0;
if(i == 0) {
/*
* eof or other error
*/
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
bp->gbuf = bp->ebuf;
return nil;
}
}
/*
* first try in remainder of buffer (gbuf doesn't change)
*/
ip = (char*)bp->ebuf - i;
ep = memchr(ip, delim, i);
if(ep) {
j = (ep - ip) + 1;
bp->icount += j;
return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
}
/*
* copy data to beginning of buffer
*/
if(i < bp->bsize)
memmove(bp->bbuf, ip, i);
bp->gbuf = bp->bbuf;
/*
* append to buffer looking for the delim
*/
p = nil;
for(;;){
ip = (char*)bp->bbuf + i;
while(i < bp->bsize) {
j = read(bp->fid, ip, bp->bsize-i);
if(j <= 0 && i == 0)
return p;
if(j <= 0 && i > 0){
/*
* end of file but no delim. pretend we got a delim
* by making the delim \0 and smashing it with nulldelim.
*/
j = 1;
ep = ip;
delim = '\0';
nulldelim = 1;
*ep = delim; /* there will be room for this */
}else{
bp->offset += j;
ep = memchr(ip, delim, j);
}
i += j;
if(ep) {
/*
* found in new piece
* copy back up and reset everything
*/
ip = (char*)bp->ebuf - i;
if(i < bp->bsize){
memmove(ip, bp->bbuf, i);
bp->gbuf = (unsigned char*)ip;
}
j = (ep - (char*)bp->bbuf) + 1;
bp->icount = j - i;
return badd(p, &bp->rdline, ip, j, delim, nulldelim);
}
ip += j;
}
/*
* full buffer without finding; add to user string and continue
*/
p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
i = 0;
bp->icount = 0;
bp->gbuf = bp->ebuf;
}
}

45
libbio/bread.c Normal file
View File

@ -0,0 +1,45 @@
#include "plan9.h"
#include <bio.h>
long
Bread(Biobuf *bp, void *ap, long count)
{
long c;
unsigned char *p;
int i, n, ic;
p = ap;
c = count;
ic = bp->icount;
while(c > 0) {
n = -ic;
if(n > c)
n = c;
if(n == 0) {
if(bp->state != Bractive)
break;
i = read(bp->fid, bp->bbuf, bp->bsize);
if(i <= 0) {
bp->state = Bracteof;
if(i < 0)
bp->state = Binactive;
break;
}
bp->gbuf = bp->bbuf;
bp->offset += i;
if(i < bp->bsize) {
memmove(bp->ebuf-i, bp->bbuf, i);
bp->gbuf = bp->ebuf-i;
}
ic = -i;
continue;
}
memmove(p, bp->ebuf+ic, n);
c -= n;
ic += n;
p += n;
}
bp->icount = ic;
return count-c;
}

60
libbio/bseek.c Normal file
View File

@ -0,0 +1,60 @@
#include "plan9.h"
#include <bio.h>
off_t
Bseek(Biobuf *bp, off_t offset, int base)
{
vlong n, d;
int bufsz;
switch(bp->state) {
default:
fprint(2, "Bseek: unknown state %d\n", bp->state);
return Beof;
case Bracteof:
bp->state = Bractive;
bp->icount = 0;
bp->gbuf = bp->ebuf;
case Bractive:
n = offset;
if(base == 1) {
n += Boffset(bp);
base = 0;
}
/*
* try to seek within buffer
*/
if(base == 0) {
d = n - Boffset(bp);
bufsz = bp->ebuf - bp->gbuf;
if(-bufsz <= d && d <= bufsz){
bp->icount += d;
if(d >= 0) {
if(bp->icount <= 0)
return n;
} else {
if(bp->ebuf - bp->gbuf >= -bp->icount)
return n;
}
}
}
/*
* reset the buffer
*/
n = lseek(bp->fid, n, base);
bp->icount = 0;
bp->gbuf = bp->ebuf;
break;
case Bwactive:
Bflush(bp);
n = lseek(bp->fid, offset, base);
break;
}
bp->offset = n;
return n;
}

36
libbio/bvprint.c Normal file
View File

@ -0,0 +1,36 @@
#include "plan9.h"
#include <bio.h>
static int
fmtBflush(Fmt *f)
{
Biobuf *bp;
bp = f->farg;
bp->ocount = (char*)f->to - (char*)f->stop;
if(Bflush(bp) < 0)
return 0;
f->stop = bp->ebuf;
f->to = (char*)f->stop + bp->ocount;
f->start = f->to;
return 1;
}
int
Bvprint(Biobuf *bp, char *fmt, va_list arg)
{
int n;
Fmt f;
f.runes = 0;
f.stop = bp->ebuf;
f.start = (char*)f.stop + bp->ocount;
f.to = f.start;
f.flush = fmtBflush;
f.farg = bp;
f.nfmt = 0;
n = fmtvprint(&f, fmt, arg);
bp->ocount = (char*)f.to - (char*)f.stop;
return n;
}

38
libbio/bwrite.c Normal file
View File

@ -0,0 +1,38 @@
#include "plan9.h"
#include <bio.h>
long
Bwrite(Biobuf *bp, void *ap, long count)
{
long c;
unsigned char *p;
int i, n, oc;
p = ap;
c = count;
oc = bp->ocount;
while(c > 0) {
n = -oc;
if(n > c)
n = c;
if(n == 0) {
if(bp->state != Bwactive)
return Beof;
i = write(bp->fid, bp->bbuf, bp->bsize);
if(i != bp->bsize) {
bp->state = Binactive;
return Beof;
}
bp->offset += i;
oc = -bp->bsize;
continue;
}
memmove(bp->ebuf+oc, p, n);
oc += n;
c -= n;
p += n;
}
bp->ocount = oc;
return count-c;
}

48
libfmt/Makefile Normal file
View File

@ -0,0 +1,48 @@
ROOT= ..
include ${ROOT}/mk/hdr.mk
VERSION=2.0
TARG=libfmt
NUM=\
charstod\
pow10\
nan64
OBJ=\
dofmt\
dorfmt\
errfmt\
fltfmt\
fmt\
fmtfd\
fmtfdflush\
fmtlock\
fmtprint\
fmtquote\
fmtrune\
fmtstr\
fmtvprint\
fprint\
print\
runefmtstr\
runeseprint\
runesmprint\
runesnprint\
runesprint\
runevseprint\
runevsmprint\
runevsnprint\
seprint\
smprint\
snprint\
sprint\
strtod\
vfprint\
vseprint\
vsmprint\
vsnprint\
$(NUM)
include ${ROOT}/mk/lib.mk

25
libfmt/NOTICE Normal file
View File

@ -0,0 +1,25 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
This is a Unix port of the Plan 9 formatted I/O package.
Please send comments about the packaging
to Russ Cox <rsc@swtch.com>.
----
This software is also made available under the Lucent Public License
version 1.02; see http://plan9.bell-labs.com/plan9dist/license.html

5
libfmt/README Normal file
View File

@ -0,0 +1,5 @@
This software was packaged for Unix by Russ Cox.
Please send comments to rsc@swtch.com.
http://swtch.com/plan9port/unix

85
libfmt/charstod.c Normal file
View File

@ -0,0 +1,85 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
}

537
libfmt/dofmt.c Normal file
View File

@ -0,0 +1,537 @@
/*
* 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 "plan9.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;
}
}
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(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 i, j;
Rune r;
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){
i = 0;
for(j=0; j<f->prec && s[i]; j++)
i += chartorune(&r, s+i);
return __fmtcpy(f, s, j, i);
}
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;
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':
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;
}
}
p = buf + sizeof buf - 1;
n = 0;
if(isv){
while(vu){
i = vu % base;
vu /= base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
}
*p-- = conv[i];
n++;
}
}else{
while(u){
i = u % base;
u /= base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
}
*p-- = conv[i];
n++;
}
}
if(n == 0){
*p-- = '0';
n = 1;
}
for(w = f->prec; n < w && p > buf+3; n++)
*p-- = '0';
if(neg || (fl & (FmtSign|FmtSpace)))
n++;
if(fl & FmtSharp){
if(base == 16)
n += 2;
else if(base == 8){
if(p[1] == '0')
fl &= ~FmtSharp;
else
n++;
}
}
if((fl & FmtZero) && !(fl & (FmtLeft|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;
}

61
libfmt/dorfmt.c Normal file
View File

@ -0,0 +1,61 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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, (Rune*)fmt, 1);
if(fmt == nil)
return -1;
}
return 0; /* not reached */
}

28
libfmt/errfmt.c Normal file
View File

@ -0,0 +1,28 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
__errfmt(Fmt *f)
{
char *s;
s = strerror(errno);
return fmtstrcpy(f, s);
}

394
libfmt/fltfmt.c Normal file
View File

@ -0,0 +1,394 @@
/*
* 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 <ctype.h>
#include <fmt.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
enum
{
FDIGIT = 30,
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,
};
#define pow10(x) fmtpow10(x)
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
xdtoa(Fmt *fmt, char *s2, double f)
{
char s1[NSIGNIF+10];
double g, h;
int e, d, i, n;
int c1, c2, c3, c4, ucase, sign, chr, prec;
prec = FDEFLT;
if(fmt->flags & FmtPrec)
prec = fmt->prec;
if(prec > FDIGIT)
prec = FDIGIT;
if(__isNaN(f)) {
strcpy(s2, "NaN");
return;
}
if(__isInf(f, 1)) {
strcpy(s2, "+Inf");
return;
}
if(__isInf(f, -1)) {
strcpy(s2, "-Inf");
return;
}
sign = 0;
if(f < 0) {
f = -f;
sign++;
}
ucase = 0;
chr = fmt->r;
if(isupper(chr)) {
ucase = 1;
chr = tolower(chr);
}
e = 0;
g = f;
if(g != 0) {
frexp(f, &e);
e = e * .301029995664;
if(e >= -150 && e <= +150) {
d = 0;
h = f;
} else {
d = e/2;
h = f * pow10(-d);
}
g = h * pow10(d-e);
while(g < 1) {
e--;
g = h * pow10(d-e);
}
while(g >= 10) {
e++;
g = h * pow10(d-e);
}
}
/*
* convert NSIGNIF digits and convert
* back to get accuracy.
*/
for(i=0; i<NSIGNIF; i++) {
d = g;
s1[i] = d + '0';
g = (g - d) * 10;
}
s1[i] = 0;
/*
* try decimal rounding to eliminate 9s
*/
c2 = prec + 1;
if(chr == 'f')
c2 += e;
if(c2 >= NSIGNIF-2) {
strcpy(s2, s1);
d = e;
s1[NSIGNIF-2] = '0';
s1[NSIGNIF-1] = '0';
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
g = strtod(s1, nil);
if(g == f)
goto found;
if(xadd(s1, NSIGNIF-3, 1)) {
e++;
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
}
g = strtod(s1, nil);
if(g == f)
goto found;
strcpy(s1, s2);
e = d;
}
/*
* convert back so s1 gets exact answer
*/
for(;;) {
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
g = strtod(s1, nil);
if(f > g) {
if(xadd(s1, NSIGNIF-1, 1))
e--;
continue;
}
if(f < g) {
if(xsub(s1, NSIGNIF-1, 1))
e++;
continue;
}
break;
}
found:
/*
* sign
*/
d = 0;
i = 0;
if(sign)
s2[d++] = '-';
else if(fmt->flags & FmtSign)
s2[d++] = '+';
else if(fmt->flags & FmtSpace)
s2[d++] = ' ';
/*
* copy into final place
* c1 digits of leading '0'
* c2 digits from conversion
* c3 digits of trailing '0'
* c4 digits after '.'
*/
c1 = 0;
c2 = prec + 1;
c3 = 0;
c4 = prec;
switch(chr) {
default:
if(xadd(s1, c2, 5))
e++;
break;
case 'g':
/*
* decide on 'e' of 'f' style convers
*/
if(xadd(s1, c2, 5))
e++;
if(e >= -5 && e <= prec) {
c1 = -e - 1;
c4 = prec - e;
chr = 'h'; // flag for 'f' style
}
break;
case 'f':
if(xadd(s1, c2+e, 5))
e++;
c1 = -e;
if(c1 > prec)
c1 = c2;
c2 += e;
break;
}
/*
* clean up c1 c2 and c3
*/
if(c1 < 0)
c1 = 0;
if(c2 < 0)
c2 = 0;
if(c2 > NSIGNIF) {
c3 = c2-NSIGNIF;
c2 = NSIGNIF;
}
/*
* copy digits
*/
while(c1 > 0) {
if(c1+c2+c3 == c4)
s2[d++] = '.';
s2[d++] = '0';
c1--;
}
while(c2 > 0) {
if(c2+c3 == c4)
s2[d++] = '.';
s2[d++] = s1[i++];
c2--;
}
while(c3 > 0) {
if(c3 == c4)
s2[d++] = '.';
s2[d++] = '0';
c3--;
}
/*
* strip trailing '0' on g conv
*/
if(fmt->flags & FmtSharp) {
if(0 == c4)
s2[d++] = '.';
} else
if(chr == 'g' || chr == 'h') {
for(n=d-1; n>=0; n--)
if(s2[n] != '0')
break;
for(i=n; i>=0; i--)
if(s2[i] == '.') {
d = n;
if(i != n)
d++;
break;
}
}
if(chr == 'e' || chr == 'g') {
if(ucase)
s2[d++] = 'E';
else
s2[d++] = 'e';
c1 = e;
if(c1 < 0) {
s2[d++] = '-';
c1 = -c1;
} else
s2[d++] = '+';
if(c1 >= 100) {
s2[d++] = c1/100 + '0';
c1 = c1%100;
}
s2[d++] = c1/10 + '0';
s2[d++] = c1%10 + '0';
}
s2[d] = 0;
}
static int
floatfmt(Fmt *fmt, double f)
{
char s[FDIGIT+10];
xdtoa(fmt, s, f);
fmt->flags &= FmtWidth|FmtLeft;
__fmtcpy(fmt, s, strlen(s), strlen(s));
return 0;
}
int
__efgfmt(Fmt *f)
{
double d;
d = va_arg(f->args, double);
return floatfmt(f, d);
}

218
libfmt/fmt.c Normal file
View File

@ -0,0 +1,218 @@
/*
* 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 "plan9.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,
'G', __efgfmt,
'S', __runesfmt, /* Plan 9 addition */
'X', __ifmt,
'b', __ifmt, /* Plan 9 addition */
'c', __charfmt,
'd', __ifmt,
'e', __efgfmt,
'f', __efgfmt,
'g', __efgfmt,
'h', __flagfmt,
'l', __flagfmt,
'n', __countfmt,
'o', __ifmt,
'p', __ifmt,
'r', __errfmt,
's', __strfmt,
'u', __flagfmt,
'x', __ifmt,
0, nil,
};
int (*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, int (*f)(Fmt*))
{
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;
}
}

116
libfmt/fmtdef.h Normal file
View File

@ -0,0 +1,116 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
/*
* dofmt -- format to a buffer
* the number of characters formatted is returned,
* or -1 if there was an error.
* if the buffer is ever filled, flush is called.
* it should reset the buffer and return whether formatting should continue.
*/
typedef int (*Fmts)(Fmt*);
typedef struct Quoteinfo Quoteinfo;
struct Quoteinfo
{
int quoted; /* if set, string must be quoted */
int nrunesin; /* number of input runes that can be accepted */
int nbytesin; /* number of input bytes that can be accepted */
int nrunesout; /* number of runes that will be generated */
int nbytesout; /* number of bytes that will be generated */
};
/* Edit .+1,/^$/ |cfn |grep -v static | grep __ */
double __Inf(int sign);
double __NaN(void);
int __badfmt(Fmt *f);
int __charfmt(Fmt *f);
int __countfmt(Fmt *f);
int __efgfmt(Fmt *fmt);
int __errfmt(Fmt *f);
int __flagfmt(Fmt *f);
int __fmtFdFlush(Fmt *f);
int __fmtcpy(Fmt *f, const void *vm, int n, int sz);
void* __fmtdispatch(Fmt *f, void *fmt, int isrunes);
void * __fmtflush(Fmt *f, void *t, int len);
void __fmtlock(void);
int __fmtpad(Fmt *f, int n);
double __fmtpow10(int n);
int __fmtrcpy(Fmt *f, const void *vm, int n);
void __fmtunlock(void);
int __ifmt(Fmt *f);
int __isInf(double d, int sign);
int __isNaN(double d);
int __needsquotes(char *s, int *quotelenp);
int __percentfmt(Fmt *f);
void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
int __quotestrfmt(int runesin, Fmt *f);
int __rfmtpad(Fmt *f, int n);
int __runefmt(Fmt *f);
int __runeneedsquotes(Rune *r, int *quotelenp);
int __runesfmt(Fmt *f);
int __strfmt(Fmt *f);
#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)
#ifdef va_copy
# define VA_COPY(a,b) va_copy(a,b)
# define VA_END(a) va_end(a)
#else
# define VA_COPY(a,b) (a) = (b)
# define VA_END(a)
#endif

46
libfmt/fmtfd.c Normal file
View File

@ -0,0 +1,46 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
}

34
libfmt/fmtfdflush.c Normal file
View File

@ -0,0 +1,34 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <unistd.h>
#include "plan9.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;
}

379
libfmt/fmtinstall.3 Normal file
View File

@ -0,0 +1,379 @@
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.TH FMTINSTALL 3
.SH NAME
fmtinstall, dofmt, dorfmt, fmtprint, fmtvprint, fmtrune, fmtstrcpy, fmtrunestrcpy, fmtfdinit, fmtfdflush, fmtstrinit, fmtstrflush, runefmtstrinit, runefmtstrflush, errfmt \- support for user-defined print formats and output routines
.SH SYNOPSIS
.B #include <utf.h>
.br
.B #include <fmt.h>
.PP
.ft L
.nf
.ta \w' 'u +\w' 'u +\w' 'u +\w' 'u +\w' 'u
typedef struct Fmt Fmt;
struct Fmt{
uchar runes; /* output buffer is runes or chars? */
void *start; /* of buffer */
void *to; /* current place in the buffer */
void *stop; /* end of the buffer; overwritten if flush fails */
int (*flush)(Fmt*); /* called when to == stop */
void *farg; /* to make flush a closure */
int nfmt; /* num chars formatted so far */
va_list args; /* args passed to dofmt */
int r; /* % format Rune */
int width;
int prec;
ulong flags;
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtZero = FmtSign << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtFlag = FmtComma << 1
};
.fi
.PP
.B
.ta \w'\fLchar* 'u
.PP
.B
int fmtfdinit(Fmt *f, int fd, char *buf, int nbuf);
.PP
.B
int fmtfdflush(Fmt *f);
.PP
.B
int fmtstrinit(Fmt *f);
.PP
.B
char* fmtstrflush(Fmt *f);
.PP
.B
int runefmtstrinit(Fmt *f);
.PP
.B
Rune* runefmtstrflush(Fmt *f);
.PP
.B
int fmtinstall(int c, int (*fn)(Fmt*));
.PP
.B
int dofmt(Fmt *f, char *fmt);
.PP
.B
int dorfmt(Fmt*, Rune *fmt);
.PP
.B
int fmtprint(Fmt *f, char *fmt, ...);
.PP
.B
int fmtvprint(Fmt *f, char *fmt, va_list v);
.PP
.B
int fmtrune(Fmt *f, int r);
.PP
.B
int fmtstrcpy(Fmt *f, char *s);
.PP
.B
int fmtrunestrcpy(Fmt *f, Rune *s);
.PP
.B
int errfmt(Fmt *f);
.SH DESCRIPTION
The interface described here allows the construction of custom
.IR print (3)
verbs and output routines.
In essence, they provide access to the workings of the formatted print code.
.PP
The
.IR print (3)
suite maintains its state with a data structure called
.BR Fmt .
A typical call to
.IR print (3)
or its relatives initializes a
.B Fmt
structure, passes it to subsidiary routines to process the output,
and finishes by emitting any saved state recorded in the
.BR Fmt .
The details of the
.B Fmt
are unimportant to outside users, except insofar as the general
design influences the interface.
The
.B Fmt
records whether the output is in runes or bytes,
the verb being processed, its precision and width,
and buffering parameters.
Most important, it also records a
.I flush
routine that the library will call if a buffer overflows.
When printing to a file descriptor, the flush routine will
emit saved characters and reset the buffer; when printing
to an allocated string, it will resize the string to receive more output.
The flush routine is nil when printing to fixed-size buffers.
User code need never provide a flush routine; this is done internally
by the library.
.SS Custom output routines
To write a custom output routine, such as an error handler that
formats and prints custom error messages, the output sequence can be run
from outside the library using the routines described here.
There are two main cases: output to an open file descriptor
and output to a string.
.PP
To write to a file descriptor, call
.I fmtfdinit
to initialize the local
.B Fmt
structure
.IR f ,
giving the file descriptor
.IR fd ,
the buffer
.IR buf ,
and its size
.IR nbuf .
Then call
.IR fmtprint
or
.IR fmtvprint
to generate the output.
These behave like
.B fprint
(see
.IR print (3))
or
.B vfprint
except that the characters are buffered until
.I fmtfdflush
is called and the return value is either 0 or \-1.
A typical example of this sequence appears in the Examples section.
.PP
The same basic sequence applies when outputting to an allocated string:
call
.I fmtstrinit
to initialize the
.BR Fmt ,
then call
.I fmtprint
and
.I fmtvprint
to generate the output.
Finally,
.I fmtstrflush
will return the allocated string, which should be freed after use.
To output to a rune string, use
.I runefmtstrinit
and
.IR runefmtstrflush .
Regardless of the output style or type,
.I fmtprint
or
.I fmtvprint
generates the characters.
.SS Custom format verbs
.I Fmtinstall
is used to install custom verbs and flags labeled by character
.IR c ,
which may be any non-zero Unicode character.
.I Fn
should be declared as
.IP
.EX
int fn(Fmt*)
.EE
.PP
.IB Fp ->r
is the flag or verb character to cause
.I fn
to be called.
In
.IR fn ,
.IB fp ->width ,
.IB fp ->prec
are the width and precision, and
.IB fp ->flags
the decoded flags for the verb (see
.IR print (3)
for a description of these items).
The standard flag values are:
.B FmtSign
.RB ( + ),
.B FmtLeft
.RB ( - ),
.B FmtSpace
.RB ( '\ ' ),
.B FmtSharp
.RB ( # ),
.B FmtComma
.RB ( , ),
.B FmtLong
.RB ( l ),
.B FmtShort
.RB ( h ),
.B FmtUnsigned
.RB ( u ),
and
.B FmtVLong
.RB ( ll ).
The flag bits
.B FmtWidth
and
.B FmtPrec
identify whether a width and precision were specified.
.PP
.I Fn
is passed a pointer to the
.B Fmt
structure recording the state of the output.
If
.IB fp ->r
is a verb (rather than a flag),
.I fn
should use
.B Fmt->args
to fetch its argument from the list,
then format it, and return zero.
If
.IB fp ->r
is a flag,
.I fn
should return one.
All interpretation of
.IB fp ->width\f1,
.IB fp ->prec\f1,
and
.IB fp-> flags
is left up to the conversion routine.
.I Fmtinstall
returns 0 if the installation succeeds, \-1 if it fails.
.PP
.IR Fmtprint
and
.IR fmtvprint
may be called to
help prepare output in custom conversion routines.
However, these functions clear the width, precision, and flags.
Both functions return 0 for success and \-1 for failure.
.PP
The functions
.I dofmt
and
.I dorfmt
are the underlying formatters; they
use the existing contents of
.B Fmt
and should be called only by sophisticated conversion routines.
These routines return the number of characters (bytes of UTF or runes)
produced.
.PP
Some internal functions may be useful to format primitive types.
They honor the width, precision and flags as described in
.IR print (3).
.I Fmtrune
formats a single character
.BR r .
.I Fmtstrcpy
formats a string
.BR s ;
.I fmtrunestrcpy
formats a rune string
.BR s .
.I Errfmt
formats the system error string.
All these routines return zero for successful execution.
Conversion routines that call these functions will work properly
regardless of whether the output is bytes or runes.
.\" .PP
.\" .IR 2c (1)
.\" describes the C directive
.\" .B #pragma
.\" .B varargck
.\" that can be used to provide type-checking for custom print verbs and output routines.
.SH EXAMPLES
This function prints an error message with a variable
number of arguments and then quits.
Compared to the corresponding example in
.IR print (3),
this version uses a smaller buffer, will never truncate
the output message, but might generate multiple
.B write
system calls to produce its output.
.IP
.EX
.ta 6n +6n +6n +6n +6n +6n +6n +6n +6n
#pragma varargck argpos error 1
void fatal(char *fmt, ...)
{
Fmt f;
char buf[64];
va_list arg;
fmtfdinit(&f, 1, buf, sizeof buf);
fmtprint(&f, "fatal: ");
va_start(arg, fmt);
fmtvprint(&f, fmt, arg);
va_end(arg);
fmtprint(&f, "\en");
fmtfdflush(&f);
exits("fatal error");
}
.EE
.PP
This example adds a verb to print complex numbers.
.IP
.EX
typedef
struct {
double r, i;
} Complex;
#pragma varargck type "X" Complex
int
Xfmt(Fmt *f)
{
Complex c;
c = va_arg(f->args, Complex);
return fmtprint(f, "(%g,%g)", c.r, c.i);
}
main(...)
{
Complex x = (Complex){ 1.5, -2.3 };
fmtinstall('X', Xfmt);
print("x = %X\en", x);
}
.EE
.SH SOURCE
.B http://swtch.com/plan9port/unix
.SH SEE ALSO
.IR print (3),
.IR utf (7)
.SH DIAGNOSTICS
These routines return negative numbers or nil for errors and set
.IR errstr .

27
libfmt/fmtlock.c Normal file
View File

@ -0,0 +1,27 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
void
__fmtlock(void)
{
}
void
__fmtunlock(void)
{
}

48
libfmt/fmtprint.c Normal file
View File

@ -0,0 +1,48 @@
/*
* 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 "plan9.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_COPY(va, f->args);
VA_END(f->args);
va_start(f->args, fmt);
n = dofmt(f, fmt);
va_end(f->args);
f->flags = 0;
f->width = 0;
f->prec = 0;
VA_COPY(f->args,va);
VA_END(va);
if(n >= 0)
return 0;
return n;
}

264
libfmt/fmtquote.c Normal file
View File

@ -0,0 +1,264 @@
/*
* 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 "plan9.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--){
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 nin, outlen;
Rune *r;
char *s;
Quoteinfo q;
nin = -1;
if(f->flags&FmtPrec)
nin = f->prec;
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, nin, 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;
}

40
libfmt/fmtrune.c Normal file
View File

@ -0,0 +1,40 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
}

27
libfmt/fmtstr.c Normal file
View File

@ -0,0 +1,27 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
char*
fmtstrflush(Fmt *f)
{
if(f->start == nil)
return nil;
*(char*)f->to = '\0';
return (char*)f->start;
}

49
libfmt/fmtvprint.c Normal file
View File

@ -0,0 +1,49 @@
/*
* 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 "plan9.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_COPY(va,f->args);
VA_END(f->args);
VA_COPY(f->args,args);
n = dofmt(f, fmt);
f->flags = 0;
f->width = 0;
f->prec = 0;
VA_END(f->args);
VA_COPY(f->args,va);
VA_END(va);
if(n >= 0)
return 0;
return n;
}

29
libfmt/fprint.c Normal file
View File

@ -0,0 +1,29 @@
/*
* 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 "plan9.h"
#include "fmt.h"
#include "fmtdef.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;
}

BIN
libfmt/libfmt.a Normal file

Binary file not shown.

67
libfmt/nan64.c Normal file
View File

@ -0,0 +1,67 @@
/*
* 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 "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
#if defined (__APPLE__) || (__powerpc__)
#define _NEEDLL
#endif
static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001;
static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000;
static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
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;
}

57
libfmt/pow10.c Normal file
View File

@ -0,0 +1,57 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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);
}

482
libfmt/print.3 Normal file
View File

@ -0,0 +1,482 @@
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.\" diffs from /usr/local/plan9/man/man3/print.3:
.\"
.\" - include different headers
.\" - drop reference to bio(3)
.\" - change exits to exit
.\" - text about unsigned verbs
.\" - source pointer
.\"
.TH PRINT 3
.SH NAME
print, fprint, sprint, snprint, seprint, smprint, runesprint, runesnprint, runeseprint, runesmprint, vfprint, vsnprint, vseprint, vsmprint, runevsnprint, runevseprint, runevsmprint \- 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:
a buffered form
is described in
.IR bio (3).
.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 complete UTF-8 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 = seprint(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 SOURCE
.B http://swtch.com/plan9port/unix
.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 and syntax are missing.
Also, and distinctly not a bug,
.I print
and friends generate
.SM UTF
rather than
.SM ASCII.
.PP
There is no
.IR runeprint ,
.IR 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 .

29
libfmt/print.c Normal file
View File

@ -0,0 +1,29 @@
/*
* 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 "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
print(char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vfprint(1, fmt, args);
va_end(args);
return n;
}

27
libfmt/runefmtstr.c Normal file
View File

@ -0,0 +1,27 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <stdlib.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
Rune*
runefmtstrflush(Fmt *f)
{
if(f->start == nil)
return nil;
*(Rune*)f->to = '\0';
return f->start;
}

30
libfmt/runeseprint.c Normal file
View File

@ -0,0 +1,30 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
}

30
libfmt/runesmprint.c Normal file
View File

@ -0,0 +1,30 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
}

31
libfmt/runesnprint.c Normal file
View File

@ -0,0 +1,31 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
}

30
libfmt/runesprint.c Normal file
View File

@ -0,0 +1,30 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
}

40
libfmt/runevseprint.c Normal file
View File

@ -0,0 +1,40 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
VA_COPY(f.args,args);
dofmt(&f, fmt);
VA_END(f.args);
*(Rune*)f.to = '\0';
return (Rune*)f.to;
}

91
libfmt/runevsmprint.c Normal file
View File

@ -0,0 +1,91 @@
/*
* 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.
*/
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
* different pointers than the standard malloc.
*/
#include <stdlib.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
static int
runeFmtStrFlush(Fmt *f)
{
Rune *s;
int n;
if(f->start == nil)
return 0;
n = (int)f->farg;
n *= 2;
s = (Rune*)f->start;
f->start = realloc(s, sizeof(Rune)*n);
if(f->start == nil){
f->farg = nil;
f->to = nil;
f->stop = nil;
free(s);
return 0;
}
f->farg = (void*)n;
f->to = (Rune*)f->start + ((Rune*)f->to - s);
f->stop = (Rune*)f->start + n - 1;
return 1;
}
int
runefmtstrinit(Fmt *f)
{
int n;
memset(f, 0, sizeof *f);
f->runes = 1;
n = 32;
f->start = malloc(sizeof(Rune)*n);
if(f->start == nil)
return -1;
f->to = f->start;
f->stop = (Rune*)f->start + n - 1;
f->flush = runeFmtStrFlush;
f->farg = (void*)n;
f->nfmt = 0;
return 0;
}
/*
* print into an allocated string buffer
*/
Rune*
runevsmprint(char *fmt, va_list args)
{
Fmt f;
int n;
if(runefmtstrinit(&f) < 0)
return nil;
VA_COPY(f.args,args);
n = dofmt(&f, fmt);
VA_END(f.args);
if(f.start == nil)
return nil;
if(n < 0){
free(f.start);
return nil;
}
*(Rune*)f.to = '\0';
return (Rune*)f.start;
}

39
libfmt/runevsnprint.c Normal file
View File

@ -0,0 +1,39 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.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;
VA_COPY(f.args,args);
dofmt(&f, fmt);
VA_END(f.args);
*(Rune*)f.to = '\0';
return (Rune*)f.to - buf;
}

29
libfmt/seprint.c Normal file
View File

@ -0,0 +1,29 @@
/*
* 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 "plan9.h"
#include "fmt.h"
#include "fmtdef.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;
}

29
libfmt/smprint.c Normal file
View File

@ -0,0 +1,29 @@
/*
* 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 "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
char*
smprint(char *fmt, ...)
{
va_list args;
char *p;
va_start(args, fmt);
p = vsmprint(fmt, args);
va_end(args);
return p;
}

30
libfmt/snprint.c Normal file
View File

@ -0,0 +1,30 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.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;
}

39
libfmt/sprint.c Normal file
View File

@ -0,0 +1,39 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <fmt.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
sprint(char *buf, char *fmt, ...)
{
int n;
uint len;
va_list args;
len = 1<<30; /* big number, but sprint is deprecated anyway */
/*
* on PowerPC, the stack is near the top of memory, so
* we must be sure not to overflow a 32-bit pointer.
*/
if(buf+len < buf)
len = -(uint)buf-1;
va_start(args, fmt);
n = vsnprint(buf, len, fmt, args);
va_end(args);
return n;
}

532
libfmt/strtod.c Normal file
View File

@ -0,0 +1,532 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
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:;
}
}
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;
}

44
libfmt/test.c Normal file
View File

@ -0,0 +1,44 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include <stdarg.h>
#include <utf.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.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 %.18g\n", 2e25, 2e25);
print("%2.18g\n", 1.0);
print("%2.18f\n", 1.0);
print("%f\n", 3.1415927/4);
print("%d\n", 23);
print("%i\n", 23);
print("%0.10d\n", 12345);
return 0;
}

9
libfmt/test2.c Normal file
View File

@ -0,0 +1,9 @@
#include <stdarg.h>
#include <utf.h>
#include <fmt.h>
int
main(int argc, char **argv)
{
print("%020.10d\n", 100);
}

52
libfmt/test3.c Normal file
View File

@ -0,0 +1,52 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
void
test(char *fmt, ...)
{
va_list arg;
char fmtbuf[100], stdbuf[100];
va_start(arg, fmt);
vsnprint(fmtbuf, sizeof fmtbuf, fmt, arg);
va_end(arg);
va_start(arg, fmt);
vsnprint(stdbuf, sizeof stdbuf, fmt, arg);
va_end(arg);
if(strcmp(fmtbuf, stdbuf) != 0)
print("fmt %s: fmt=\"%s\" std=\"%s\"\n", fmt, fmtbuf, stdbuf);
print("fmt %s: %s\n", fmt, fmtbuf);
}
int
main(int argc, char *argv[])
{
test("%f", 3.14159);
test("%f", 3.14159e10);
test("%f", 3.14159e-10);
test("%e", 3.14159);
test("%e", 3.14159e10);
test("%e", 3.14159e-10);
test("%g", 3.14159);
test("%g", 3.14159e10);
test("%g", 3.14159e-10);
test("%g", 2e25);
test("%.18g", 2e25);
test("%2.18g", 1.0);
test("%2.18f", 1.0);
test("%f", 3.1415927/4);
test("%20.10d", 12345);
test("%0.10d", 12345);
return 0;
}

33
libfmt/vfprint.c Normal file
View File

@ -0,0 +1,33 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.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));
VA_COPY(f.args,args);
n = dofmt(&f, fmt);
VA_END(f.args);
if(n > 0 && __fmtFdFlush(&f) == 0)
return -1;
return n;
}

39
libfmt/vseprint.c Normal file
View File

@ -0,0 +1,39 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.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;
VA_COPY(f.args,args);
dofmt(&f, fmt);
VA_END(f.args);
*(char*)f.to = '\0';
return (char*)f.to;
}

88
libfmt/vsmprint.c Normal file
View File

@ -0,0 +1,88 @@
/*
* 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.
*/
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
* different pointers than the standard malloc.
*/
#include <stdlib.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
static int
fmtStrFlush(Fmt *f)
{
char *s;
int n;
if(f->start == nil)
return 0;
n = (int)f->farg;
n *= 2;
s = (char*)f->start;
f->start = realloc(s, n);
if(f->start == nil){
f->farg = nil;
f->to = nil;
f->stop = nil;
free(s);
return 0;
}
f->farg = (void*)n;
f->to = (char*)f->start + ((char*)f->to - s);
f->stop = (char*)f->start + n - 1;
return 1;
}
int
fmtstrinit(Fmt *f)
{
int n;
memset(f, 0, sizeof *f);
f->runes = 0;
n = 32;
f->start = malloc(n);
if(f->start == nil)
return -1;
f->to = f->start;
f->stop = (char*)f->start + n - 1;
f->flush = fmtStrFlush;
f->farg = (void*)n;
f->nfmt = 0;
return 0;
}
/*
* print into an allocated string buffer
*/
char*
vsmprint(char *fmt, va_list args)
{
Fmt f;
int n;
if(fmtstrinit(&f) < 0)
return nil;
VA_COPY(f.args,args);
n = dofmt(&f, fmt);
VA_END(f.args);
if(n < 0){
free(f.start);
return nil;
}
return fmtstrflush(&f);
}

39
libfmt/vsnprint.c Normal file
View File

@ -0,0 +1,39 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.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;
VA_COPY(f.args,args);
dofmt(&f, fmt);
VA_END(f.args);
*(char*)f.to = '\0';
return (char*)f.to - buf;
}

17
libregexp/Makefile Normal file
View File

@ -0,0 +1,17 @@
ROOT= ..
include ${ROOT}/mk/hdr.mk
VERSION=2.0
TARG=libregexp9
OBJ=\
regcomp\
regerror\
regexec\
regsub\
regaux\
rregexec\
rregsub\
include ${ROOT}/mk/lib.mk

25
libregexp/NOTICE Normal file
View File

@ -0,0 +1,25 @@
/*
* The authors of this software is Rob Pike.
* 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 regular expression library.
Please send comments about the packaging
to Russ Cox <rsc@swtch.com>.
----
This software is also made available under the Lucent Public License
version 1.02; see http://plan9.bell-labs.com/plan9dist/license.html

5
libregexp/README Normal file
View File

@ -0,0 +1,5 @@
This software was packaged for Unix by Russ Cox.
Please send comments to rsc@swtch.com.
http://swtch.com/plan9port/unix

112
libregexp/regaux.c Normal file
View File

@ -0,0 +1,112 @@
#include "plan9.h"
#include "regexp9.h"
#include "regcomp.h"
/*
* save a new match in mp
*/
extern void
_renewmatch(Resub *mp, int ms, Resublist *sp)
{
int i;
if(mp==0 || ms<=0)
return;
if(mp[0].s.sp==0 || sp->m[0].s.sp<mp[0].s.sp ||
(sp->m[0].s.sp==mp[0].s.sp && sp->m[0].e.ep>mp[0].e.ep)){
for(i=0; i<ms && i<NSUBEXP; i++)
mp[i] = sp->m[i];
for(; i<ms; i++)
mp[i].s.sp = mp[i].e.ep = 0;
}
}
/*
* Note optimization in _renewthread:
* *lp must be pending when _renewthread called; if *l has been looked
* at already, the optimization is a bug.
*/
extern Relist*
_renewthread(Relist *lp, /* _relist to add to */
Reinst *ip, /* instruction to add */
int ms,
Resublist *sep) /* pointers to subexpressions */
{
Relist *p;
for(p=lp; p->inst; p++){
if(p->inst == ip){
if(sep->m[0].s.sp < p->se.m[0].s.sp){
if(ms > 1)
p->se = *sep;
else
p->se.m[0] = sep->m[0];
}
return 0;
}
}
p->inst = ip;
if(ms > 1)
p->se = *sep;
else
p->se.m[0] = sep->m[0];
(++p)->inst = 0;
return p;
}
/*
* same as renewthread, but called with
* initial empty start pointer.
*/
extern Relist*
_renewemptythread(Relist *lp, /* _relist to add to */
Reinst *ip, /* instruction to add */
int ms,
char *sp) /* pointers to subexpressions */
{
Relist *p;
for(p=lp; p->inst; p++){
if(p->inst == ip){
if(sp < p->se.m[0].s.sp) {
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.sp = sp;
}
return 0;
}
}
p->inst = ip;
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.sp = sp;
(++p)->inst = 0;
return p;
}
extern Relist*
_rrenewemptythread(Relist *lp, /* _relist to add to */
Reinst *ip, /* instruction to add */
int ms,
Rune *rsp) /* pointers to subexpressions */
{
Relist *p;
for(p=lp; p->inst; p++){
if(p->inst == ip){
if(rsp < p->se.m[0].s.rsp) {
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.rsp = rsp;
}
return 0;
}
}
p->inst = ip;
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.rsp = rsp;
(++p)->inst = 0;
return p;
}

559
libregexp/regcomp.c Normal file
View File

@ -0,0 +1,559 @@
#include <setjmp.h>
#include <stdlib.h>
#include "plan9.h"
#include "regexp9.h"
#include "regcomp.h"
enum {
FALSE,
TRUE,
};
/*
* Parser Information
*/
typedef struct Node Node;
struct Node
{
Reinst* first;
Reinst* last;
};
#define NSTACK 20
static Node andstack[NSTACK];
static Node *andp;
static int atorstack[NSTACK];
static int* atorp;
static int cursubid; /* id of current subexpression */
static int subidstack[NSTACK]; /* parallel to atorstack */
static int* subidp;
static int lastwasand; /* Last token was operand */
static int nbra;
static char* exprp; /* pointer to next character in source expression */
static int lexdone;
static int nclass;
static Reclass*classp;
static Reinst* freep;
static int errors;
static Rune yyrune; /* last lex'd rune */
static Reclass*yyclassp; /* last lex'd class */
/* predeclared crap */
static void operator(int);
static void pushand(Reinst*, Reinst*);
static void pushator(int);
static void evaluntil(int);
static int bldcclass(void);
static jmp_buf regkaboom;
static void
rcerror(char *s)
{
errors++;
regerror(s);
longjmp(regkaboom, 1);
}
static Reinst*
newinst(int t)
{
freep->type = t;
freep->u2.left = 0;
freep->u1.right = 0;
return freep++;
}
static void
operand(int t)
{
Reinst *i;
if(lastwasand)
operator(CAT); /* catenate is implicit */
i = newinst(t);
if(t == CCLASS || t == NCCLASS)
i->u1.cp = yyclassp;
if(t == RUNE)
i->u1.r = yyrune;
pushand(i, i);
lastwasand = TRUE;
}
static void
operator(int t)
{
if(t==RBRA && --nbra<0)
rcerror("unmatched right paren");
if(t==LBRA){
if(++cursubid >= NSUBEXP)
rcerror ("too many subexpressions");
nbra++;
if(lastwasand)
operator(CAT);
} else
evaluntil(t);
if(t != RBRA)
pushator(t);
lastwasand = FALSE;
if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
lastwasand = TRUE; /* these look like operands */
}
static void
regerr2(char *s, int c)
{
char buf[100];
char *cp = buf;
while(*s)
*cp++ = *s++;
*cp++ = c;
*cp = '\0';
rcerror(buf);
}
static void
cant(char *s)
{
char buf[100];
strcpy(buf, "can't happen: ");
strcat(buf, s);
rcerror(buf);
}
static void
pushand(Reinst *f, Reinst *l)
{
if(andp >= &andstack[NSTACK])
cant("operand stack overflow");
andp->first = f;
andp->last = l;
andp++;
}
static void
pushator(int t)
{
if(atorp >= &atorstack[NSTACK])
cant("operator stack overflow");
*atorp++ = t;
*subidp++ = cursubid;
}
static Node*
popand(int op)
{
Reinst *inst;
if(andp <= &andstack[0]){
regerr2("missing operand for ", op);
inst = newinst(NOP);
pushand(inst,inst);
}
return --andp;
}
static int
popator(void)
{
if(atorp <= &atorstack[0])
cant("operator stack underflow");
--subidp;
return *--atorp;
}
static void
evaluntil(int pri)
{
Node *op1, *op2;
Reinst *inst1, *inst2;
while(pri==RBRA || atorp[-1]>=pri){
switch(popator()){
default:
rcerror("unknown operator in evaluntil");
break;
case LBRA: /* must have been RBRA */
op1 = popand('(');
inst2 = newinst(RBRA);
inst2->u1.subid = *subidp;
op1->last->u2.next = inst2;
inst1 = newinst(LBRA);
inst1->u1.subid = *subidp;
inst1->u2.next = op1->first;
pushand(inst1, inst2);
return;
case OR:
op2 = popand('|');
op1 = popand('|');
inst2 = newinst(NOP);
op2->last->u2.next = inst2;
op1->last->u2.next = inst2;
inst1 = newinst(OR);
inst1->u1.right = op1->first;
inst1->u2.left = op2->first;
pushand(inst1, inst2);
break;
case CAT:
op2 = popand(0);
op1 = popand(0);
op1->last->u2.next = op2->first;
pushand(op1->first, op2->last);
break;
case STAR:
op2 = popand('*');
inst1 = newinst(OR);
op2->last->u2.next = inst1;
inst1->u1.right = op2->first;
pushand(inst1, inst1);
break;
case PLUS:
op2 = popand('+');
inst1 = newinst(OR);
op2->last->u2.next = inst1;
inst1->u1.right = op2->first;
pushand(op2->first, inst1);
break;
case QUEST:
op2 = popand('?');
inst1 = newinst(OR);
inst2 = newinst(NOP);
inst1->u2.left = inst2;
inst1->u1.right = op2->first;
op2->last->u2.next = inst2;
pushand(inst1, inst2);
break;
}
}
}
static Reprog*
optimize(Reprog *pp)
{
Reinst *inst, *target;
int size;
Reprog *npp;
Reclass *cl;
int diff;
/*
* get rid of NOOP chains
*/
for(inst=pp->firstinst; inst->type!=END; inst++){
target = inst->u2.next;
while(target->type == NOP)
target = target->u2.next;
inst->u2.next = target;
}
/*
* The original allocation is for an area larger than
* necessary. Reallocate to the actual space used
* and then relocate the code.
*/
size = sizeof(Reprog) + (freep - pp->firstinst)*sizeof(Reinst);
npp = realloc(pp, size);
if(npp==0 || npp==pp)
return pp;
diff = (char *)npp - (char *)pp;
freep = (Reinst *)((char *)freep + diff);
for(inst=npp->firstinst; inst<freep; inst++){
switch(inst->type){
case OR:
case STAR:
case PLUS:
case QUEST:
*(char **)&inst->u1.right += diff;
break;
case CCLASS:
case NCCLASS:
*(char **)&inst->u1.right += diff;
cl = inst->u1.cp;
*(char **)&cl->end += diff;
break;
}
*(char **)&inst->u2.left += diff;
}
*(char **)&npp->startinst += diff;
return npp;
}
#ifdef DEBUG
static void
dumpstack(void){
Node *stk;
int *ip;
print("operators\n");
for(ip=atorstack; ip<atorp; ip++)
print("0%o\n", *ip);
print("operands\n");
for(stk=andstack; stk<andp; stk++)
print("0%o\t0%o\n", stk->first->type, stk->last->type);
}
static void
dump(Reprog *pp)
{
Reinst *l;
Rune *p;
l = pp->firstinst;
do{
print("%d:\t0%o\t%d\t%d", l-pp->firstinst, l->type,
l->u2.left-pp->firstinst, l->u1.right-pp->firstinst);
if(l->type == RUNE)
print("\t%C\n", l->u1.r);
else if(l->type == CCLASS || l->type == NCCLASS){
print("\t[");
if(l->type == NCCLASS)
print("^");
for(p = l->u1.cp->spans; p < l->u1.cp->end; p += 2)
if(p[0] == p[1])
print("%C", p[0]);
else
print("%C-%C", p[0], p[1]);
print("]\n");
} else
print("\n");
}while(l++->type);
}
#endif
static Reclass*
newclass(void)
{
if(nclass >= NCLASS)
regerr2("too many character classes; limit", NCLASS+'0');
return &(classp[nclass++]);
}
static int
nextc(Rune *rp)
{
if(lexdone){
*rp = 0;
return 1;
}
exprp += chartorune(rp, exprp);
if(*rp == '\\'){
exprp += chartorune(rp, exprp);
return 1;
}
if(*rp == 0)
lexdone = 1;
return 0;
}
static int
lex(int literal, int dot_type)
{
int quoted;
quoted = nextc(&yyrune);
if(literal || quoted){
if(yyrune == 0)
return END;
return RUNE;
}
switch(yyrune){
case 0:
return END;
case '*':
return STAR;
case '?':
return QUEST;
case '+':
return PLUS;
case '|':
return OR;
case '.':
return dot_type;
case '(':
return LBRA;
case ')':
return RBRA;
case '^':
return BOL;
case '$':
return EOL;
case '[':
return bldcclass();
}
return RUNE;
}
static int
bldcclass(void)
{
int type;
Rune r[NCCRUNE];
Rune *p, *ep, *np;
Rune rune;
int quoted;
/* we have already seen the '[' */
type = CCLASS;
yyclassp = newclass();
/* look ahead for negation */
/* SPECIAL CASE!!! negated classes don't match \n */
ep = r;
quoted = nextc(&rune);
if(!quoted && rune == '^'){
type = NCCLASS;
quoted = nextc(&rune);
*ep++ = '\n';
*ep++ = '\n';
}
/* parse class into a set of spans */
for(; ep<&r[NCCRUNE];){
if(rune == 0){
rcerror("malformed '[]'");
return 0;
}
if(!quoted && rune == ']')
break;
if(!quoted && rune == '-'){
if(ep == r){
rcerror("malformed '[]'");
return 0;
}
quoted = nextc(&rune);
if((!quoted && rune == ']') || rune == 0){
rcerror("malformed '[]'");
return 0;
}
*(ep-1) = rune;
} else {
*ep++ = rune;
*ep++ = rune;
}
quoted = nextc(&rune);
}
/* sort on span start */
for(p = r; p < ep; p += 2){
for(np = p; np < ep; np += 2)
if(*np < *p){
rune = np[0];
np[0] = p[0];
p[0] = rune;
rune = np[1];
np[1] = p[1];
p[1] = rune;
}
}
/* merge spans */
np = yyclassp->spans;
p = r;
if(r == ep)
yyclassp->end = np;
else {
np[0] = *p++;
np[1] = *p++;
for(; p < ep; p += 2)
if(p[0] <= np[1]){
if(p[1] > np[1])
np[1] = p[1];
} else {
np += 2;
np[0] = p[0];
np[1] = p[1];
}
yyclassp->end = np+2;
}
return type;
}
static Reprog*
regcomp1(char *s, int literal, int dot_type)
{
int token;
Reprog *volatile pp;
/* get memory for the program */
pp = malloc(sizeof(Reprog) + 6*sizeof(Reinst)*strlen(s));
if(pp == 0){
regerror("out of memory");
return 0;
}
freep = pp->firstinst;
classp = pp->class;
errors = 0;
if(setjmp(regkaboom))
goto out;
/* go compile the sucker */
lexdone = 0;
exprp = s;
nclass = 0;
nbra = 0;
atorp = atorstack;
andp = andstack;
subidp = subidstack;
lastwasand = FALSE;
cursubid = 0;
/* Start with a low priority operator to prime parser */
pushator(START-1);
while((token = lex(literal, dot_type)) != END){
if((token&0300) == OPERATOR)
operator(token);
else
operand(token);
}
/* Close with a low priority operator */
evaluntil(START);
/* Force END */
operand(END);
evaluntil(START);
#ifdef DEBUG
dumpstack();
#endif
if(nbra)
rcerror("unmatched left paren");
--andp; /* points to first and only operand */
pp->startinst = andp->first;
#ifdef DEBUG
dump(pp);
#endif
pp = optimize(pp);
#ifdef DEBUG
print("start: %d\n", andp->first-pp->firstinst);
dump(pp);
#endif
out:
if(errors){
free(pp);
pp = 0;
}
return pp;
}
extern Reprog*
regcomp(char *s)
{
return regcomp1(s, 0, ANY);
}
extern Reprog*
regcomplit(char *s)
{
return regcomp1(s, 1, ANY);
}
extern Reprog*
regcompnl(char *s)
{
return regcomp1(s, 0, ANYNL);
}

15
libregexp/regerror.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <plan9.h>
#include <regexp9.h>
void
regerror(char *s)
{
char buf[132];
strcpy(buf, "regerror: ");
strcat(buf, s);
strcat(buf, "\n");
write(2, buf, strlen(buf));
exits("regerr");
}

Some files were not shown because too many files have changed in this diff Show More