Add locale charset crud.

This commit is contained in:
Kris Maglione 2010-06-06 05:07:24 -04:00
parent 154f750e0a
commit 20f317dd6a
21 changed files with 502 additions and 68 deletions

View File

@ -1,6 +1,7 @@
Copyright © 2006-2009 Kris Maglione <maglione.k@gmail.com> Copyright © 2006-2010 Kris Maglione <maglione.k@gmail.com>
Copyright © 2003-2006 Anselm R Garbe <anselm@garbe.us> Copyright © 2003-2006 Anselm R Garbe <anselm@garbe.us>
Portions Copyright © 2002 by Lucent Technologies.
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -41,8 +41,6 @@ main(int argc, char *argv[]) {
usage(); usage();
}ARGEND; }ARGEND;
setlocale(LC_CTYPE, "");
initdisplay(); initdisplay();
s = ARGF(); s = ARGF();

View File

@ -186,8 +186,10 @@ main(int argc, char *argv[]) {
int i; int i;
long ndump; long ndump;
quotefmtinstall(); setlocale(LC_CTYPE, "");
fmtinstall('r', errfmt); fmtinstall('r', errfmt);
quotefmtinstall();
screen_hint = PointerScreen; screen_hint = PointerScreen;
find = strstr; find = strstr;
@ -227,7 +229,7 @@ main(int argc, char *argv[]) {
cmdsep = EARGF(usage()); cmdsep = EARGF(usage());
break; break;
case 'v': case 'v':
print("%s", version); lprint(1, "%s", version);
return 0; return 0;
default: default:
usage(); usage();
@ -236,8 +238,6 @@ main(int argc, char *argv[]) {
if(argc) if(argc)
usage(); usage();
setlocale(LC_CTYPE, "");
initdisplay(); initdisplay();
xext_init(); xext_init();

View File

@ -90,9 +90,9 @@ next:
if(input.filter_start == 0 && input.pos == input.end) if(input.filter_start == 0 && input.pos == input.end)
menu_cmd(CMPL_FIRST, 0); menu_cmd(CMPL_FIRST, 0);
if(!motion && matchidx && !strcmp(input.string, matchidx->string)) if(!motion && matchidx && !strcmp(input.string, matchidx->string))
print("%s", matchidx->retstring); lprint(1, "%s", matchidx->retstring);
else else
print("%s", input.string); lprint(1, "%s", input.string);
break; break;
case REJECT: case REJECT:
srv.running = false; srv.running = false;

View File

@ -130,6 +130,7 @@ main(int argc, char *argv[]) {
ulong win; ulong win;
char *s; char *s;
setlocale(LC_CTYPE, "");
fmtinstall('E', fmtevent); fmtinstall('E', fmtevent);
ARGBEGIN{ ARGBEGIN{
@ -140,14 +141,12 @@ main(int argc, char *argv[]) {
direction = DVertical; direction = DVertical;
break; break;
case 'v': case 'v':
print("%s", version); lprint(1, "%s", version);
return 0; return 0;
default: default:
usage(); usage();
}ARGEND; }ARGEND;
setlocale(LC_CTYPE, "");
initdisplay(); initdisplay();
testwin = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, testwin = createwindow(&scr.root, Rect(0, 0, 1, 1), 0,

View File

@ -116,7 +116,6 @@ main(int argc, char *argv[]) {
program_args = argv; program_args = argv;
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
fmtinstall('r', errfmt); fmtinstall('r', errfmt);
fmtinstall('E', fmtevent); fmtinstall('E', fmtevent);
@ -163,7 +162,7 @@ main(int argc, char *argv[]) {
debug++; debug++;
break; break;
case 'v': case 'v':
print("%s", version); lprint(1, "%s", version);
return 0; return 0;
default: default:
usage(); usage();
@ -184,7 +183,7 @@ main(int argc, char *argv[]) {
if(tray.selection == nil) if(tray.selection == nil)
fatal("Another system tray is already running."); fatal("Another system tray is already running.");
if(tray.selection->oldowner) if(tray.selection->oldowner)
print("Replacing currently running system tray.\n"); lprint(1, "Replacing currently running system tray.\n");
xext_init(); xext_init();
tray_init(); tray_init();

View File

@ -630,7 +630,6 @@ client_kill(Client *c, bool nice) {
ulong *pid; ulong *pid;
long n; long n;
c->dead = 1;
if(!nice) { if(!nice) {
getprop_textlist(&c->w, "WM_CLIENT_MACHINE", &host); getprop_textlist(&c->w, "WM_CLIENT_MACHINE", &host);
n = getprop_ulong(&c->w, Net("WM_PID"), "CARDINAL", 0, &pid, 1); n = getprop_ulong(&c->w, Net("WM_PID"), "CARDINAL", 0, &pid, 1);
@ -642,6 +641,7 @@ client_kill(Client *c, bool nice) {
XKillClient(display, c->w.xid); XKillClient(display, c->w.xid);
} }
else if(c->proto & ProtoDelete) { else if(c->proto & ProtoDelete) {
c->dead = 1;
client_message(c, "WM_DELETE_WINDOW", 0); client_message(c, "WM_DELETE_WINDOW", 0);
ewmh_checkresponsive(c); ewmh_checkresponsive(c);
} }

View File

@ -335,12 +335,12 @@ main(int argc, char *argv[]) {
char *wmiirc, *s; char *wmiirc, *s;
int i; int i;
quotefmtinstall(); setlocale(LC_CTYPE, "");
fmtinstall('r', errfmt); fmtinstall('r', errfmt);
fmtinstall('a', afmt); fmtinstall('a', afmt);
fmtinstall('C', Cfmt); fmtinstall('C', Cfmt);
extern int fmtevent(Fmt*);
fmtinstall('E', fmtevent); fmtinstall('E', fmtevent);
quotefmtinstall();
wmiirc = "wmiirc"; wmiirc = "wmiirc";
@ -353,7 +353,7 @@ extern int fmtevent(Fmt*);
wmiirc = EARGF(usage()); wmiirc = EARGF(usage());
break; break;
case 'v': case 'v':
print("%s", version); lprint(1, "%s", version);
exit(0); exit(0);
case 'D': case 'D':
s = EARGF(usage()); s = EARGF(usage());
@ -368,7 +368,6 @@ extern int fmtevent(Fmt*);
if(argc) if(argc)
usage(); usage();
setlocale(LC_CTYPE, "");
starting = true; starting = true;
initdisplay(); initdisplay();

View File

@ -116,7 +116,7 @@ main(int argc, char **argv)
ARGBEGIN{ ARGBEGIN{
case 'v': case 'v':
print("%s\n", version); lprint(1, "%s\n", version);
return 0; return 0;
case 'a': case 'a':
address = EARGF(usage()); address = EARGF(usage());
@ -172,8 +172,8 @@ main(int argc, char **argv)
void void
usage(void) usage(void)
{ {
fprintf(stderr, "usage: %s -v\n", argv0); lprint(2, "usage: %s -v\n", argv0);
fprintf(stderr, " %s [-a <address>] [-i <arg>] menitem[:command] ...\n", argv0); lprint(2, " %s [-a <address>] [-i <arg>] menitem[:command] ...\n", argv0);
exit(0); exit(0);
} }
@ -210,8 +210,7 @@ run_menu(void)
XNextEvent(display, &ev); XNextEvent(display, &ev);
switch (ev.type) { switch (ev.type) {
default: default:
fprintf(stderr, "%s: unknown ev.type %d\n", lprint(2, "%s: unknown ev.type %d\n", argv0, ev.type);
argv0, ev.type);
break; break;
case ButtonRelease: case ButtonRelease:
i = ev.xbutton.y / high; i = ev.xbutton.y / high;
@ -220,7 +219,7 @@ run_menu(void)
else if(i < 0 || i >= numitems) else if(i < 0 || i >= numitems)
return; return;
printf("%s\n", commands[i]); lprint(1, "%s\n", commands[i]);
return; return;
case ButtonPress: case ButtonPress:
case MotionNotify: case MotionNotify:

View File

@ -4,23 +4,28 @@
#define IXP_NO_P9_ #define IXP_NO_P9_
#define IXP_P9_STRUCTS #define IXP_P9_STRUCTS
#include <dirent.h> #include <dirent.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/signal.h> #include <sys/signal.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <wchar.h>
#include <ixp.h> #include <ixp.h>
#include <stuff/util.h> #include <stuff/util.h>
#include <bio.h> #include <bio.h>
#include <fmt.h> #include <fmt.h>
static IxpClient *client; static IxpClient* client;
static Biobuf *outbuf; static Biobuf* outbuf;
static bool binary;
static void static void
usage(void) { usage(void) {
fprint(1, lprint(1,
"usage: %s [-a <address>] {create | ls [-dlp] | read | remove | write} <file>\n" "usage: %s [-a <address>] [-b] {create | ls [-dlp] | read | remove | write} <file>\n"
" %s [-a <address>] xwrite <file> <data>\n" " %s [-a <address>] xwrite <file> <data>\n"
" %s -v\n", argv0, argv0, argv0); " %s -v\n", argv0, argv0, argv0);
exit(1); exit(1);
@ -31,21 +36,110 @@ errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf()); return fmtstrcpy(f, ixp_errbuf());
} }
static bool
flush(IxpCFid *fid, char *in, int len, bool binary) {
static mbstate_t state;
static char buf[IXP_MAX_MSG];
static char *out = buf, *outend = buf + sizeof buf;
char *inend;
wchar_t w;
Rune r;
int res;
if(binary)
return ixp_write(fid, in, len) == len;
inend = in + len;
do {
if(in == nil || out + UTFmax > outend) {
if(ixp_write(fid, buf, out - buf) != out - buf)
return false;
out = buf;
}
if(in == nil) {
state = (mbstate_t){0};
return true;
}
switch((res = mbrtowc(&w, in, inend - in, &state))) {
case -1:
return false;
case 0:
case -2:
return true;
default:
in += res;
r = w < Runemax ? w : Runesync;
out += runetochar(out, &r);
}
} while(in < inend);
return true;
}
static bool
unflush(int fd, char *in, int len, bool binary) {
static mbstate_t state;
static char buf[IXP_MAX_MSG], extra[UTFmax];
static char *out = buf, *outend = buf + sizeof buf;
static int nextra;
char *start;
Rune r;
int res, n;
if(binary)
return write(fd, in, len) == len;
if(in) {
if((n = nextra)) {
nextra = 0;
while(len > 0 && n < UTFmax && !fullrune(extra, n)) {
extra[n++] = *in++;
len--;
}
unflush(fd, extra, n, binary);
}
n = utfnlen(in, len);
}
start = in;
do {
if(in == nil || out + MB_LEN_MAX > outend) {
if(write(fd, buf, out - buf) != out - buf)
return false;
out = buf;
}
if(in == nil || n == 0) {
state = (mbstate_t){0};
return true;
}
in += chartorune(&r, in);
n--;
res = wcrtomb(out, r, &state);
if(res == -1)
*out++ = '?';
else
out += res;
} while(n > 0);
if(in < start + len) {
nextra = min(sizeof extra, len - (in - start));
memcpy(extra, in, nextra);
}
return true;
}
/* Utility Functions */ /* Utility Functions */
static void static void
write_data(IxpCFid *fid, char *name) { write_data(IxpCFid *fid, char *name, bool binary) {
void *buf; char buf[IXP_MAX_MSG];
int len; int len;
buf = emalloc(fid->iounit);; while((len = read(0, buf, fid->iounit)) > 0)
for(;;) { if(!flush(fid, buf, len, binary))
len = read(0, buf, fid->iounit);
if(len <= 0)
break;
if(ixp_write(fid, buf, len) != len)
fatal("cannot write file %q\n", name); fatal("cannot write file %q\n", name);
}
free(buf); if(!binary)
flush(fid, nil, 0, binary);
} }
static int static int
@ -101,14 +195,14 @@ print_stat(Stat *s, int lflag, char *file, int pflag) {
file = ""; file = "";
if(lflag) if(lflag)
Bprint(outbuf, "%s %s %s %5llud %s %s%s%s\n", Blprint(outbuf, "%s %s %s %5llud %s %s%s%s\n",
modestr(s->mode), s->uid, s->gid, s->length, modestr(s->mode), s->uid, s->gid, s->length,
timestr(s->mtime), file, slash, s->name); timestr(s->mtime), file, slash, s->name);
else { else {
if((s->mode&P9_DMDIR) && strcmp(s->name, "/")) if((s->mode&P9_DMDIR) && strcmp(s->name, "/"))
Bprint(outbuf, "%s%s%s/\n", file, slash, s->name); Blprint(outbuf, "%s%s%s/\n", file, slash, s->name);
else else
Bprint(outbuf, "%s%s%s\n", file, slash, s->name); Blprint(outbuf, "%s%s%s\n", file, slash, s->name);
} }
} }
@ -128,7 +222,7 @@ xwrite(int argc, char *argv[]) {
if(fid == nil) if(fid == nil)
fatal("Can't open file '%s': %r\n", file); fatal("Can't open file '%s': %r\n", file);
write_data(fid, file); write_data(fid, file, binary);
ixp_close(fid); ixp_close(fid);
return 0; return 0;
} }
@ -160,7 +254,7 @@ xawrite(int argc, char *argv[]) {
strcat(buf, " "); strcat(buf, " ");
} }
if(ixp_write(fid, buf, nbuf) == -1) if(!(flush(fid, buf, nbuf, binary) && (binary || flush(fid, 0, 0, binary))))
fatal("cannot write file '%s': %r\n", file); fatal("cannot write file '%s': %r\n", file);
ixp_close(fid); ixp_close(fid);
free(buf); free(buf);
@ -183,7 +277,7 @@ xcreate(int argc, char *argv[]) {
fatal("Can't create file '%s': %r\n", file); fatal("Can't create file '%s': %r\n", file);
if((fid->qid.type&P9_DMDIR) == 0) if((fid->qid.type&P9_DMDIR) == 0)
write_data(fid, file); write_data(fid, file, binary);
ixp_close(fid); ixp_close(fid);
return 0; return 0;
} }
@ -200,7 +294,7 @@ xremove(int argc, char *argv[]) {
file = EARGF(usage()); file = EARGF(usage());
do { do {
if(!ixp_remove(client, file)) if(!ixp_remove(client, file))
fprint(2, "%s: Can't remove file '%s': %r\n", argv0, file); lprint(2, "%s: Can't remove file '%s': %r\n", argv0, file);
}while((file = ARGF())); }while((file = ARGF()));
return 0; return 0;
} }
@ -226,11 +320,13 @@ xread(int argc, char *argv[]) {
buf = emalloc(fid->iounit); buf = emalloc(fid->iounit);
while((count = ixp_read(fid, buf, fid->iounit)) > 0) while((count = ixp_read(fid, buf, fid->iounit)) > 0)
write(1, buf, count); unflush(1, buf, count, binary);
if(!binary)
unflush(1, 0, 0, binary);
ixp_close(fid); ixp_close(fid);
if(count == -1) if(count == -1)
fprint(2, "%s: cannot read file '%s': %r\n", argv0, file); lprint(2, "%s: cannot read file '%s': %r\n", argv0, file);
} while((file = ARGF())); } while((file = ARGF()));
return 0; return 0;
@ -327,7 +423,7 @@ xnamespace(int argc, char *argv[]) {
path = ixp_namespace(); path = ixp_namespace();
if(path == nil) if(path == nil)
fatal("can't find namespace: %r\n"); fatal("can't find namespace: %r\n");
Bprint(outbuf, "%s\n", path); Blprint(outbuf, "%s\n", path);
return 0; return 0;
} }
@ -345,6 +441,7 @@ xproglist(int argc, char *argv[]) {
}ARGEND; }ARGEND;
while((dir = ARGF())) while((dir = ARGF()))
/* Don't use Blprint. wimenu expects UTF-8. */
if((d = opendir(dir))) { if((d = opendir(dir))) {
while((de = readdir(d))) while((de = readdir(d)))
if(access(de->d_name, X_OK)) if(access(de->d_name, X_OK))
@ -418,14 +515,20 @@ main(int argc, char *argv[]) {
exectab *tab; exectab *tab;
int ret; int ret;
setlocale(LC_ALL, "");
binary = utf8locale();
quotefmtinstall(); quotefmtinstall();
fmtinstall('r', errfmt); fmtinstall('r', errfmt);
address = getenv("WMII_ADDRESS"); address = getenv("WMII_ADDRESS");
ARGBEGIN{ ARGBEGIN{
case 'b':
binary = true;
break;
case 'v': case 'v':
print("%s-" VERSION ", " COPYRIGHT "\n", argv0); lprint(1, "%s-" VERSION ", " COPYRIGHT "\n", argv0);
exit(0); exit(0);
case 'a': case 'a':
address = EARGF(usage()); address = EARGF(usage());

View File

@ -3,7 +3,9 @@
*/ */
#include <stuff/geom.h> #include <stuff/geom.h>
#include <langinfo.h>
#include <stdarg.h> #include <stdarg.h>
#include <bio.h>
#include <fmt.h> #include <fmt.h>
#include <regexp9.h> #include <regexp9.h>
@ -26,6 +28,12 @@ enum {
GInvert = 1<<0, GInvert = 1<<0,
}; };
enum {
Runemax = (1 << (sizeof(Rune) * 8)) - 1,
};
#define utf8locale() (!strcmp(nl_langinfo(CODESET), "UTF-8"))
#ifdef VARARGCK #ifdef VARARGCK
# pragma varargck argpos _die 3 # pragma varargck argpos _die 3
# pragma varargck argpos fatal 1 # pragma varargck argpos fatal 1
@ -35,7 +43,8 @@ enum {
#define strlcat stuff_strlcat #define strlcat stuff_strlcat
#define strcasestr stuff_strcasestr #define strcasestr stuff_strcasestr
int Blprint(Biobuf*, const char*, ...);
int Bvlprint(Biobuf*, const char*, va_list);
void _die(char*, int, char*, ...); void _die(char*, int, char*, ...);
void backtrace(char*); void backtrace(char*);
void closeexec(int); void closeexec(int);
@ -48,12 +57,16 @@ char* estrdup(const char*);
char* estrndup(const char*, uint); char* estrndup(const char*, uint);
void fatal(const char*, ...); void fatal(const char*, ...);
void* freelater(void*); void* freelater(void*);
int getbase(const char**, long*); int getbase(const char**, long*);
bool getint(const char*, int*); bool getint(const char*, int*);
bool getlong(const char*, long*); bool getlong(const char*, long*);
bool getulong(const char*, ulong*); bool getulong(const char*, ulong*);
void grep(char**, Reprog*, int); void grep(char**, Reprog*, int);
char* join(char**, char*, Fmt*); char* join(char**, char*, Fmt*);
int localefmt(Fmt*);
void localefmtinstall(void);
int localelen(char*, char*);
int lprint(int, const char*, ...);
int max(int, int); int max(int, int);
int min(int, int); int min(int, int);
uvlong nsec(void); uvlong nsec(void);
@ -64,7 +77,7 @@ int spawn3(int[3], const char*, char*[]);
int spawn3l(int[3], const char*, ...); int spawn3l(int[3], const char*, ...);
uint stokenize(char**, uint, char*, char*); uint stokenize(char**, uint, char*, char*);
char* strcasestr(const char*, const char*); char* strcasestr(const char*, const char*);
char* strend(char*, int); char* strend(char*, int);
uint strlcat(char*, const char*, uint); uint strlcat(char*, const char*, uint);
int strlcatprint(char*, int, const char*, ...); int strlcatprint(char*, int, const char*, ...);
char* sxprint(const char*, ...); char* sxprint(const char*, ...);
@ -73,6 +86,7 @@ void trim(char *str, const char *chars);
void uniq(char**); void uniq(char**);
int unquote(char*, char*[], int); int unquote(char*, char*[], int);
int utflcpy(char*, const char*, int); int utflcpy(char*, const char*, int);
int vlprint(int, const char*, va_list);
char* vsxprint(const char*, va_list); char* vsxprint(const char*, va_list);
extern char buffer[8092]; extern char buffer[8092];
extern char* _buffer; extern char* _buffer;

View File

@ -34,6 +34,12 @@ OBJ=\
event/selectionrequest \ event/selectionrequest \
event/unmapnotify \ event/unmapnotify \
event/xtime \ event/xtime \
fmt/blprint \
fmt/bvlprint \
fmt/localefmt \
fmt/localelen \
fmt/lprint \
fmt/vlprint \
geom/get_sticky \ geom/get_sticky \
geom/quadrant \ geom/quadrant \
geom/rect_contains_p \ geom/rect_contains_p \

View File

@ -0,0 +1,19 @@
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
#include <bio.h>
int
Blprint(Biobuf *bp, const char *fmt, ...)
{
va_list arg;
int n;
va_start(arg, fmt);
n = Bvlprint(bp, fmt, arg);
va_end(arg);
return n;
}

View File

@ -0,0 +1,58 @@
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
#include <bio.h>
static int
fmtBlflush(Fmt *f)
{
mbstate_t state;
Biobuf *bp;
Rune *rp, *rend;
int res;
bp = f->farg;
rend = f->to;
state = (mbstate_t){0};
for(rp=(Rune*)f->start; rp < rend; rp++) {
if(MB_LEN_MAX + bp->ocount > 0 && Bflush(bp) < 0)
return 0;
res = wcrtomb((char*)bp->ebuf + bp->ocount, *rp, &state);
if(res == -1)
Bputc(bp, '?');
else
bp->ocount += res;
}
f->to = f->start;
return 1;
}
int
Bvlprint(Biobuf *bp, const char *fmt, va_list args)
{
Fmt f;
Rune buf[256];
int res;
if(utf8locale())
return Bvprint(bp, fmt, args);
f.runes = 1;
f.start = (char*)buf;
f.to = (char*)buf;
f.stop = (char*)(buf + nelem(buf) - 1);
f.flush = fmtBlflush;
f.farg = bp;
f.nfmt = 0;
va_copy(f.args, args);
res = dofmt(&f, fmt);
va_end(f.args);
if(res > 0 && fmtBlflush(&f) == 0)
return -1;
return res;
}

10
lib/libstuff/fmt/fmtdef.h Normal file
View File

@ -0,0 +1,10 @@
#include <stuff/util.h>
#include <langinfo.h>
#include <limits.h>
#include <string.h>
#include <wchar.h>
extern void* __fmtflush(Fmt *f, void *t, int len);
extern int __fmtpad(Fmt *f, int n);
extern int __rfmtpad(Fmt *f, int n);

View File

@ -0,0 +1,107 @@
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
static bool
pad(Fmt *f, int len) {
if(f->flags & FmtWidth) {
if(f->runes)
return __rfmtpad(f, f->width - len) >= 0;
return __fmtpad(f, f->width - len) >= 0;
}
return true;
}
int
localefmt(Fmt *f) {
mbstate_t state;
Rune *rp, *rend;
char *sp, *send, *str, *end;
Rune r;
wchar_t w;
int res, count, rlen;
str = va_arg(f->args, char*);
if(utf8locale()) {
/* We handle precision in bytes, fmtstrcpy in characters */
if(f->flags & FmtPrec)
f->prec = utfnlen(str, f->prec);
return fmtstrcpy(f, str);
}
end = 0;
if(f->flags & FmtPrec)
end = str + f->prec;
if(!(f->flags & FmtLeft) && !pad(f, localelen(str, end)))
return -1;
sp = f->to;
send = f->stop;
rp = (Rune*)f->to;
rend = (Rune*)f->stop;
count = 0;
for(state = (mbstate_t){0}; ; str += res) {
switch((res = mbrtowc(&w, str, end ? end - str : MB_LEN_MAX, &state))) {
case 0:
case -2:
break;
case -1:
w = Runesync;
res = 1;
/* Fallthrough. */
default:
count++;
if(w > Runemax)
w = Runesync;
r = w;
// print("%d %C\n", res, r);
if(f->runes) {
if(rp >= rend) {
// print("flush\n");
rp = (Rune*)__fmtflush(f, rp, sizeof *rp);
rend = (Rune*)f->stop;
if(rp == nil)
return -1;
}
*rp++ = r;
}else {
if(sp + UTFmax > send && sp + (rlen = runelen(r)) > send) {
// print("flush %d\n", rlen);
sp = __fmtflush(f, sp, rlen);
send = f->stop;
if(sp == nil)
return -1;
}
if(r < Runeself)
*sp++ = (char)r;
else
sp += runetochar(sp, &r);
}
continue;
}
if(f->runes) {
f->nfmt += rp - (Rune*)f->to;
f->to = (char*)rp;
}else {
f->nfmt += sp - (char*)f->to;
f->to = sp;
}
break;
}
if((f->flags & FmtLeft) && !pad(f, count))
return -1;
return 0;
}
void
localefmtinstall(void) {
fmtinstall('L', localefmt);
}

View File

@ -0,0 +1,33 @@
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
int
localelen(char *str, char *end) {
mbstate_t state;
size_t n, res;
if(utf8locale()) {
if(end)
return utfnlen(str, end - str);
return utflen(str);
}
state = (mbstate_t){0};
n = 0;
for(n=0;;)
switch((res = mbrtowc(nil, str, end ? end - str : MB_LEN_MAX, &state))) {
case -1:
return -1;
case 0:
case -2:
return n;
default:
n++;
str += res;
}
return n; /* Not reached. */
}

17
lib/libstuff/fmt/lprint.c Normal file
View File

@ -0,0 +1,17 @@
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
int
lprint(int fd, const char *fmt, ...) {
va_list ap;
int res;
va_start(ap, fmt);
res = vlprint(fd, fmt, ap);
va_end(ap);
return res;
}

View File

@ -0,0 +1,60 @@
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
#include <unistd.h>
static int
fmtlfdflush(Fmt *f) {
mbstate_t state;
char buf[256];
Rune *rp, *rend;
char *sp, *send;
int res;
sp = buf;
send = buf + sizeof buf - UTFmax;
rend = f->to;
state = (mbstate_t){0};
for(rp=(Rune*)f->start; rp < rend; rp++) {
res = wcrtomb(sp, *rp, &state);
if(res == -1)
*sp++ = '?'; /* Fixme? */
else
sp += res;
if(sp >= send || rp == rend - 1) {
if(write((uintptr_t)f->farg, buf, sp - buf) != sp - buf)
return 0;
sp = buf;
}
}
f->to = f->start;
return 1;
}
int
vlprint(int fd, const char *fmt, va_list args) {
Fmt f;
Rune buf[256];
int res;
if(utf8locale())
return vfprint(fd, fmt, args);
f.runes = 1;
f.start = (char*)buf;
f.to = (char*)buf;
f.stop = (char*)(buf + nelem(buf) - 1);
f.flush = fmtlfdflush;
f.farg = (void*)(uintptr_t)fd;
f.nfmt = 0;
va_copy(f.args, args);
res = dofmt(&f, fmt);
va_end(f.args);
if(res > 0 && fmtlfdflush(&f) == 0)
return -1;
return res;
}

View File

@ -210,17 +210,19 @@ Most aspects of `wmii` are controlled via the filesystem.
It is usually accessed via the wmiir(1) command, but it It is usually accessed via the wmiir(1) command, but it
can be accessed by any ``9P``, including plan9port's can be accessed by any ``9P``, including plan9port's
9P[1], and can be mounted natively on Linux via v9fs[1], 9P[1], and can be mounted natively on Linux via v9fs[1],
and on Inferno (which man run on top of Linux). and on Inferno (which man run on top of Linux). All data in the
filesystem, including filenames, is UTF-8 encoded. However, when
accessed via wmiir(1), text is automatically translated to and
from your locale encoding.
The filesystem is, as are many other 9P filesystems, entirely The filesystem is, as are many other 9P filesystems, entirely
synthetic. The files exist only in memory, and are not written synthetic. The files exist only in memory, and are not written
to disk. They are generally initiated on wmii startup via a to disk. They are generally initiated on wmii startup via a
script such as rc.wmii or wmiirc. Several files read commands, script such as wmiirc. Several files read commands, others
others simply act as if they were ordinary files (their contents simply act as if they were ordinary files (their contents are
are updated and returned exactly as written), though writing updated and returned exactly as written), though writing them
them has side-effects (such as changing key bindings). A has side-effects (such as changing key bindings). A description
description of the filesystem layout and control commands of the filesystem layout and control commands follows.
follows.
== Hierarchy == == Hierarchy ==

View File

@ -10,8 +10,8 @@ wmiir - The wmii 9P filesystem client
= SYNOPSIS = = SYNOPSIS =
wmiir [-a <address>] {create | ls [-dlp] | read | remove | write} <file> + wmiir [-a <address>] [-b] {create | ls [-dlp] | read | remove | write} <file> +
wmiir [-a <address>] xwrite <file> <data> ... + wmiir [-a <address>] [-b] xwrite <file> <data> ... +
wmiir -v wmiir -v
= DESCRIPTION = = DESCRIPTION =
@ -21,10 +21,20 @@ to its virtual filesystem by default. `wmiir` is most often used to query and
issue commands to `wmii`, both from the command line and from its `sh`-based issue commands to `wmii`, both from the command line and from its `sh`-based
configuration scripts. configuration scripts.
Since the default encoding of 9P filesystems is UTF-8, `wmiir`
assumes that all data read and written is text data and
translates to or from your locale character encoding as
necessary. When working with non-text data in a non-UTF-8
locale, the _-b_ flag should be specified to disable this
behavior.
= ARGUMENTS = = ARGUMENTS =
: -a : -a
The address at which to connect to `wmii`. The address at which to connect to `wmii`.
: -b
With the _-b_ flag, data that you intend to read or
write is treated as binary data.
: :
= COMMANDS = = COMMANDS =