mirror of https://github.com/0intro/wmii
Add Plan 9 formatted IO. Various cleanups and fixes.
This commit is contained in:
parent
29cd363e63
commit
209fb08f82
4
Makefile
4
Makefile
|
@ -7,6 +7,10 @@ PDIRS = \
|
|||
man
|
||||
|
||||
DIRS = \
|
||||
libutf \
|
||||
libfmt \
|
||||
libbio \
|
||||
libregexp\
|
||||
${PDIRS}
|
||||
|
||||
config:
|
||||
|
|
|
@ -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
|
||||
|
|
36
cmd/util.c
36
cmd/util.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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,13 +292,22 @@ 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:
|
||||
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();
|
||||
|
@ -308,6 +322,7 @@ init_traps(void) {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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(®, "^#[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(®, 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
363
cmd/wmii/utf.c
363
cmd/wmii/utf.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, ®m, 0)) {
|
||||
if(regexec(r->regex, v->name, nil, 0)) {
|
||||
char buf[sizeof r->value];
|
||||
char *toks[16];
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
48
cmd/wmiir.c
48
cmd/wmiir.c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 515 B |
|
@ -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
|
|
@ -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
|
|
@ -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])
|
||||
|
|
@ -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*);
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include "plan9.h"
|
||||
#include <bio.h>
|
||||
|
||||
int
|
||||
Bfildes(Biobuf *bp)
|
||||
{
|
||||
|
||||
return bp->fid;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 .
|
|
@ -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)
|
||||
{
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
Binary file not shown.
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 .
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdarg.h>
|
||||
#include <utf.h>
|
||||
#include <fmt.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
print("%020.10d\n", 100);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue