ref: 258e99f33c065e824340532d678b9fbcce4260c3
author: glenda <glenda@pi>
date: Thu Mar 5 12:48:53 EST 2026
first upload w chat libirc pelm and netsurf
--- /dev/null
+++ b/README
@@ -1,0 +1,1 @@
+jarred, pickled, and preserved softwares that i shall not lose.
--- /dev/null
+++ b/chat/chat.man
@@ -1,0 +1,67 @@
+.TH CHAT 1
+.SH NAME
+chat \- internet relay chat client
+.SH SYNOPSIS
+.B chat
+[
+.B -t
+] [
+.B -a
+.I address
+]
+.SH DESCRIPTION
+.I Chat
+is an
+.B IRC
+client. It connects to tcp!irc.oftc.net!6697 (see
+.IR dial (2)),
+or the server specified in the
+.B $irc
+environment variable, and reads raw
+.B IRC
+commands from standard input. Chat recognizes the following flags:
+.TP
+.B -t
+Connect using TLS.
+.TP
+.B -a
+Set the address to
+.I address.
+.PP
+.I Chat
+also recognizes the following control
+messages:
+.TP
+.B /q \fItarget\fR
+This opens a new window that relays
+messages to the
+.I target.
+The
+.I target
+can be a channel or a nick.
+The created window
+also accepts control messages.
+.TP
+.BI /x
+Closes a window and parts. If sent to
+the main window, the connection is closed
+and the program exits.
+.TP
+.B /n \fIdoofus\fR
+Change nicknames to
+.I doofus.
+.SH EXAMPLES
+Join #cat-v and then open a private
+message window with glenda:
+.br
+.ne 3
+.IP
+.EX
+chat
+/q #cat-v
+/q glenda
+.EE
+.SH SOURCE
+https://github.com/mischief/plan9
+.SH SEE ALSO
+.IR ircrc (1)
--- /dev/null
+++ b/chat/dat.h
@@ -1,0 +1,15 @@
+typedef struct Wind Wind;
+struct Wind
+{+ QLock;
+ u64int id;
+ char *target;
+
+ Channel *event; /* char* */
+
+ int kfd; /* rio cons */
+ int kpid; /* keyboard child */
+
+ Wind *prev;
+ Wind *next;
+};
--- /dev/null
+++ b/chat/fns.h
@@ -1,0 +1,13 @@
+/* util.c */
+u64int jenkinshash(char*, int);
+void riolabel(char*);
+void rioclose(void);
+int riowindow(char*);
+
+/* wind.c */
+Wind *windmk(char*);
+void windfree(Wind*);
+void windlink(Wind*, Wind*);
+void windunlink(Wind*, Wind*);
+Wind* windfind(Wind*, char*);
+void windappend(Wind*, char*, ...);
--- /dev/null
+++ b/chat/main.c
@@ -1,0 +1,315 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <thread.h>
+#include <fcall.h>
+#include <9p.h>
+#include <mp.h>
+#include <libsec.h>
+
+#include "irc.h"
+
+#include "dat.h"
+#include "fns.h"
+
+static Wind *mainwind; /* server window */
+static Irc *conn; /* our connection */
+static char *nick;
+
+static void windevents(Wind*);
+
+static void
+windproc(void *v)
+{+ char *name;
+ Wind *w;
+
+ name = v;
+
+ threadsetname("wind %s", name);+
+ /* copy ns since we fiddle with the namespace for graphics */
+ rfork(RFNAMEG);
+
+ if(riowindow("-scroll") < 0)+ sysfatal("newwindow: %r");+
+ riolabel(name);
+
+ w = windmk(name);
+ windlink(mainwind, w);
+
+ free(name);
+
+ windevents(w);
+
+ windunlink(mainwind, w);
+ if(chanclosing(w->event) == -1)
+ chanclose(w->event);
+ windfree(w);
+
+ rioclose();
+ threadexits(nil);
+}
+
+enum
+{+ CMexit,
+ CMquery,
+ CMnick,
+};
+
+Cmdtab inputtab[] =
+{+ CMexit, "x", 1,
+ CMexit, "exit", 1,
+ CMquery, "q", 2,
+ CMquery, "query", 2,
+ CMnick, "n", 2,
+ CMnick, "nick", 2,
+};
+
+static void
+windevents(Wind *w)
+{+ char *s, *name;
+ Cmdbuf *cb;
+ Cmdtab *ct;
+
+ while((s = recvp(w->event)) != nil){+ if(s[0] == '/' && strlen(s) > 1){+ cb = parsecmd(s+1, strlen(s+1));
+ ct = lookupcmd(cb, inputtab, nelem(inputtab));
+ if(ct == nil){+ windappend(w, "* invalid command %q *", cb->f[0]);
+ continue;
+ }
+
+ switch(ct->index){+ case CMexit:
+ free(cb);
+ part:
+ if(w->target != nil && w->target[0] == '#')
+ ircpart(conn, w->target);
+ goto done;
+ break;
+
+ case CMquery:
+ if(cb->f[1][0] == '#')
+ ircjoin(conn, cb->f[1]);
+
+ name = strdup(cb->f[1]);
+ proccreate(windproc, name, 8192);
+ break;
+
+ case CMnick:
+ ircnick(conn, cb->f[1]);
+ break;
+ }
+ free(cb);
+ } else {+ if(w->target != nil){+ ircprivmsg(conn, w->target, s);
+ } else {+ ircraw(conn, s);
+ }
+ }
+ free(s);
+ }
+
+ /* make sure to part on rio del */
+ if(w->target != nil && w->target[0] == '#')
+ goto part;
+
+done:
+ return;
+}
+
+static void
+on433(Irc *irc, IrcMsg*, void*)
+{+ char buf[128];
+
+ snprint(buf, sizeof buf, "%s%d", nick, 10+nrand(1000));
+ windappend(mainwind, "* nickname %q in use, switching to %q *", nick, buf);
+
+ ircnick(irc, buf);
+}
+
+// NOTICE/PRIVMSG
+static void
+msg(Irc*, IrcMsg *m, void*)
+{+ int r;
+ char buf[512], prefix[256];
+ char *s;
+ Wind *w;
+
+ /* user privmsg */
+ strcpy(prefix, m->prefix);
+ if((s = strchr(prefix, '!')) != nil)
+ *s = 0;
+
+ snprint(buf, sizeof buf, "%s⇒ ", prefix);
+ for(r = 1; r < m->nargs; r++){+ strcat(buf, " ");
+ strcat(buf, m->args[r]);
+ }
+
+ if(m->args[0][0] == '#'){+ w = windfind(mainwind, m->args[0]);
+ } else {+ w = windfind(mainwind, prefix);
+ }
+
+ if(w != nil){+ windappend(w, buf);
+ } else {+ windappend(mainwind, buf);
+ }
+}
+
+static int
+inset(char *needle, char **haystack){+ char **p;
+ for(p = haystack; *p != nil; (*p)++)
+ if(cistrcmp(needle, *p) == 0)
+ return 0;
+
+ return -1;
+}
+
+static void
+catchall(Irc*, IrcMsg *m, void*)
+{+ int i;
+ char buf[512];
+
+ if(m->cmd[0] == '_')
+ return;
+
+ char *unwanted[]={+ IRC_PING,
+ IRC_NOTICE,
+ IRC_PRIVMSG,
+ nil,
+ };
+
+ if(inset(m->cmd, unwanted) == 0)
+ return;
+
+ snprint(buf, sizeof buf, "%s⇒ ", m->prefix);
+ for(i = 1; i < m->nargs; i++){+ strcat(buf, " ");
+ strcat(buf, m->args[i]);
+ }
+
+ windappend(mainwind, buf);
+}
+
+static void
+ondisconnect(Irc *, IrcMsg*, void*)
+{+ windappend(mainwind, "* disconnected *");
+}
+
+static void
+onconnect(Irc *irc, IrcMsg*, void*)
+{+ Wind *w;
+
+ windappend(mainwind, "* connected *");
+ ircuser(irc, "none", "0", "none");
+ ircnick(irc, nick);;
+
+ qlock(mainwind);
+ for(w = mainwind; w != nil; w = w->next){+ if(w->target != nil && w->target[0] == '#')
+ ircjoin(irc, w->target);
+ }
+ qunlock(mainwind);
+}
+
+static void
+ircproc(void *v)
+{+ Irc *irc;
+
+ irc = v;
+
+ procsetname("irc %s", ircconf(irc)->address);+
+ ircrun(irc);
+}
+
+static void
+usage(void)
+{+ fprint(2, "usage: %s [-t] [-a address]\n", argv0);
+ threadexitsall("usage");+}
+
+static int
+tlsdial(Irc *, IrcConf *conf)
+{+ TLSconn c;
+ int fd;
+
+ fd = dial(conf->address, nil, nil, nil);
+ if(fd < 0)
+ return -1;
+ return tlsClient(fd, &c);
+}
+
+void
+threadmain(int argc, char *argv[])
+{+ IrcConf conf = { 0 };+ char *address = getenv("irc");+
+ ARGBEGIN{+ case 't':
+ conf.dial = tlsdial;
+ break;
+ case 'a':
+ address = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 0)
+ usage();
+
+ quotefmtinstall();
+ srand(truerand());
+
+ rfork(RFNOTEG);
+
+ if(address == nil)
+ address = "tcp!irc.oftc.net!6697";
+
+ conf.address = address;
+ nick = getuser();
+
+ riolabel(address);
+
+ mainwind = windmk(nil);
+
+ conn = ircinit(&conf);
+ irchook(conn, IRC_CONNECT, onconnect);
+ irchook(conn, IRC_DISCONNECT, ondisconnect);
+ irchook(conn, IRC_ERR_NICKNAMEINUSE, on433);
+ irchook(conn, IRC_PRIVMSG, msg);
+ irchook(conn, IRC_NOTICE, msg);
+ irchook(conn, nil, catchall);
+
+ proccreate(ircproc, conn, 16*1024);
+
+ procsetname("main window");+
+ windevents(mainwind);
+
+ postnote(PNGROUP, getpid(), "die yankee pig dog");
+ threadexitsall(nil);
+}
--- /dev/null
+++ b/chat/mkfile
@@ -1,0 +1,19 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=chat
+OFILES=\
+ main.$O\
+ util.$O\
+ wind.$O\
+
+LIB=/$objtype/lib/libirc.a
+
+MAN=/sys/man/1
+
+</sys/src/cmd/mkone
+
+install:V: man
+
+uninstall:V:
+ rm -f $BIN/$TARG $MAN/$TARG
--- /dev/null
+++ b/chat/util.c
@@ -1,0 +1,67 @@
+#include <u.h>
+#include <libc.h>
+
+u64int jenkinshash(char *key, int len)
+{+ u64int hash, i;
+ for(hash = i = 0; i < len; ++i){+ hash += key[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ return hash;
+}
+
+static void
+fwrites(char *f, char *s)
+{+ int fd;
+ fd = open(f, OWRITE);
+ if(fd > 0){+ write(fd, s, strlen(s));
+ close(fd);
+ }
+}
+
+void
+riolabel(char *label)
+{+ fwrites("/dev/label", label);+}
+
+void
+rioclose(void)
+{+ fwrites("/dev/wctl", "delete");+}
+
+/* copied from /sys/src/libdraw/newwindow.c to avoid linking in libdraw. */
+int
+riowindow(char *str)
+{+ int fd;
+ char *wsys;
+ char buf[256];
+
+ wsys = getenv("wsys");+ if(wsys == nil)
+ return -1;
+ fd = open(wsys, ORDWR);
+ if(fd < 0){+ free(wsys);
+ return -1;
+ }
+ rfork(RFNAMEG);
+ unmount(wsys, "/dev"); /* drop reference to old window */
+ free(wsys);
+ if(str)
+ snprint(buf, sizeof buf, "new %s", str);
+ else
+ strcpy(buf, "new");
+ if(mount(fd, -1, "/mnt/wsys", MREPL, buf) < 0)
+ return mount(fd, -1, "/dev", MBEFORE, buf);
+ return bind("/mnt/wsys", "/dev", MBEFORE);+}
--- /dev/null
+++ b/chat/wind.c
@@ -1,0 +1,131 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+
+#include "dat.h"
+#include "fns.h"
+
+static void
+kbdproc(void *v)
+{+ char line[512];
+ int r;
+ Wind *w;
+
+ w = v;
+
+ threadsetname("kbdproc");+
+ while((r = read(w->kfd, line, sizeof line - 1)) > 0){+ if(r > 0 && line[r] == '\n')
+ r--;
+
+ line[r] = 0;
+
+ chanprint(w->event, "%s", line);
+ }
+
+ chanclose(w->event);
+}
+
+Wind*
+windmk(char *target)
+{+ int r;
+ Wind *w;
+
+ w = mallocz(sizeof(*w), 1);
+ if(target != nil){+ for(r = 0; r < strlen(target); r++)
+ target[r] = tolower(target[r]);
+
+ w->id = jenkinshash(target, strlen(target));
+ }
+
+ if(target != nil)
+ w->target = strdup(target);
+
+ w->event = chancreate(sizeof(char*), 0);
+ w->kpid = -1;
+
+ if((w->kfd = open("/dev/cons", ORDWR)) < 0){+ sysfatal("open: %r");+ }
+
+ w->kpid = proccreate(kbdproc, w, 8192);
+ return w;
+}
+
+void
+windfree(Wind *w)
+{+ qlock(w);
+
+ if(w->kpid > 0)
+ postnote(PNPROC, w->kpid, "die yankee pig dog");
+
+ if(w->event != nil)
+ chanfree(w->event);
+
+ free(w->target);
+ free(w);
+}
+
+void
+windlink(Wind *l, Wind *w)
+{+ qlock(l);
+ w->prev = l;
+ w->next = l->next;
+ l->next = w;
+ qunlock(l);
+}
+
+void
+windunlink(Wind *l, Wind *w)
+{+ qlock(l);
+ if(w->next != nil)
+ w->next->prev = w->prev;
+ if(w->prev != nil)
+ w->prev->next = w->next;
+ qunlock(l);
+}
+
+Wind*
+windfind(Wind *l, char *target)
+{+ int r;
+ u64int id;
+ Wind *w;
+
+ for(r = 0; r < strlen(target); r++)
+ target[r] = tolower(target[r]);
+
+ id = jenkinshash(target, strlen(target));
+
+ qlock(l);
+ for(w = l; w != nil; w = w->next){+ if(w->id == id)
+ break;
+ }
+ qunlock(l);
+
+ return w;
+}
+
+void
+windappend(Wind *w, char *msg, ...)
+{+ va_list arg;
+
+ qlock(w);
+
+ va_start(arg, msg);
+ vfprint(w->kfd, msg, arg);
+ va_end(arg);
+
+ write(w->kfd, "\n", 1);
+
+ qunlock(w);
+}
--- /dev/null
+++ b/libirc/irc.c
@@ -1,0 +1,342 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include "irc.h"
+
+typedef struct Hook Hook;
+struct Hook
+{+ char what[64];
+ IrcCb *cb;
+ Hook *next;
+};
+
+struct Irc
+{+ QLock;
+
+ IrcConf *conf;
+
+ int fd;
+ Biobuf *buf;
+ Hook *head;
+
+ int run;
+};
+
+IrcMsg*
+parsemsg(char *b)
+{+ char *tok[5], *args[20];
+ int i, n, ntok, nargs;
+ IrcMsg *msg;
+
+ if(b == nil || b[0] == 0)
+ return nil;
+
+ msg = mallocz(sizeof(*msg), 1);
+ if(msg == nil)
+ return nil;
+
+ if(b[0] == ':'){+ ntok = gettokens(b, tok, 2, " ");
+ if(ntok != 2)
+ goto fail;
+ strncpy(msg->prefix, tok[0]+1, sizeof(msg->prefix)-1);
+ b = tok[1];
+ }
+
+ ntok = gettokens(b, tok, 2, ":");
+
+ nargs = gettokens(tok[0], args, nelem(args), " ");
+
+ strncpy(msg->cmd, args[0], sizeof(msg->cmd)-1);
+ n = strlen(msg->cmd);
+ for(i = 0; i < n; i++){+ msg->cmd[i] = tolower(msg->cmd[i]);
+ }
+
+ msg->nargs = nargs - 1 + (ntok > 1 ? 1 : 0);
+
+ msg->args = mallocz(msg->nargs * sizeof(char*), 1);
+ if(msg->args == nil)
+ goto fail;
+
+ for(i = 0; i < msg->nargs - (ntok > 1 ? 1 : 0); i++){+ msg->args[i] = strdup(args[i+1]);
+ }
+
+ if(ntok > 1){+ msg->args[i] = strdup(tok[1]);
+ }
+
+/*
+ fprint(2, "prefix: %s\n", msg->prefix);
+ fprint(2, "command: %s\n", msg->cmd);
+ for(i = 0; i < msg->nargs; i++){+ fprint(2, " %s\n", msg->args[i]);
+ }
+*/
+
+ return msg;
+fail:
+ free(msg);
+ return nil;
+}
+
+void
+freemsg(IrcMsg *m)
+{+ int i;
+
+ assert(m != nil);
+
+ if(m->nargs > 0){+ for(i = 0; i < m->nargs; i++)
+ free(m->args[i]);
+ free(m->args);
+ }
+
+ free(m);
+}
+
+void
+pinghandler(Irc *irc, IrcMsg *msg, void*)
+{+ if(msg->nargs > 0)
+ ircrawf(irc, "PONG :%s", msg->args[0]);
+}
+
+Irc*
+ircinit(IrcConf *conf)
+{+ Irc *c;
+
+ c = mallocz(sizeof(*c), 1);
+ if(c == nil)
+ return nil;
+
+ c->conf = conf;
+ c->fd = -1;
+ c->run = 1;
+
+ if(irchook(c, IRC_PING, pinghandler) < 0)
+ goto bad1;
+
+ return c;
+
+bad1:
+ free(c);
+ return nil;
+}
+
+void
+ircfree(Irc *irc)
+{+ Hook *h, *next;
+
+ for(h = irc->head, next = h->next; next != nil; h = next, next = next->next){+ free(h);
+ }
+
+ if(irc->buf)
+ Bterm(irc->buf);
+}
+
+static void
+callhook(Irc *irc, char *what, IrcMsg *msg){+ Hook *h;
+ IrcMsg fake;
+
+ if(msg == nil){+ msg = &fake;
+ memset(msg, 0, sizeof(*msg));
+ strcpy(msg->cmd, what);
+ }
+
+ for(h = irc->head; h != nil; h = h->next)
+ if(h->what[0] == 0 || cistrcmp(what, h->what) == 0)
+ h->cb(irc, msg, irc->conf->aux);
+}
+
+int
+ircrun(Irc *irc)
+{+ int l;
+ char *p;
+ IrcMsg *msg;
+ Biobuf *buf;
+
+ buf = nil;
+
+ for(;;){+ qlock(irc);
+ if(!irc->run)
+ break;
+ qunlock(irc);
+
+ switch(irc->fd){+ case -1:
+ callhook(irc, IRC_DIALING, nil);
+
+ if(irc->conf->dial != nil)
+ irc->fd = irc->conf->dial(irc, irc->conf);
+ else
+ irc->fd = dial(irc->conf->address, nil, nil, nil);
+
+ if(irc->fd >= 0){+ buf = Bfdopen(irc->fd, OREAD);
+ if(buf == nil){+ callhook(irc, IRC_OOM, nil);
+ break;
+ }
+
+ callhook(irc, IRC_CONNECT, nil);
+ }
+
+ sleep(5000);
+
+ break;
+ default:
+ p = Brdstr(buf, '\n', 1);
+ if(p == nil){+ // eof/maybe oom?
+ Bterm(buf);
+ buf = nil;
+ irc->fd = -1;
+ callhook(irc, IRC_DISCONNECT, nil);
+ break;
+ }
+
+ l = Blinelen(buf);
+ if(l > 0 && p[l-1] == '\r')
+ p[l-1] = 0;
+
+ if(irc->conf->debug)
+ fprint(2, "<< %s\n", p);
+
+ msg = parsemsg(p);
+ free(p);
+ if(msg == nil){+ callhook(irc, IRC_OOM, nil);
+ break;
+ }
+
+ if(strcmp(msg->cmd, IRC_PING) == 0){+ ircrawf(irc, "PONG: %s", msg->args[0]);
+ }
+
+ callhook(irc, msg->cmd, msg);
+
+ freemsg(msg);
+
+ break;
+ }
+ }
+
+ if(buf != nil)
+ Bterm(buf);
+
+ return 0;
+}
+
+int
+irchook(Irc *irc, char *what, IrcCb *cb)
+{+ Hook *h;
+
+ h = mallocz(sizeof(*h), 1);
+ if(h == nil)
+ return -1;
+
+ if(what == nil)
+ what = "";
+
+ snprint(h->what, sizeof(h->what), "%s", what);
+ h->cb = cb;
+ h->next = irc->head;
+
+ irc->head = h;
+
+ return 0;
+}
+
+IrcConf*
+ircconf(Irc *irc)
+{+ return irc->conf;
+}
+
+void
+ircterminate(Irc *irc)
+{+ qlock(irc);
+ irc->run = 0;
+ close(irc->fd);
+ qunlock(irc);
+}
+
+int
+ircraw(Irc *irc, char *msg)
+{+ int rv;
+
+ if(irc->conf->debug)
+ fprint(2, ">> %s\n", msg);
+
+ rv = write(irc->fd, msg, strlen(msg));
+ if(rv > 0)
+ rv = write(irc->fd, "\r\n", 2);
+ return rv;
+}
+
+int
+ircrawf(Irc *irc, char *fmt, ...)
+{+ char tmp[512];
+ va_list arg;
+
+ va_start(arg, fmt);
+
+ tmp[0] = 0;
+ vsnprint(tmp, sizeof(tmp), fmt, arg);
+
+ return ircraw(irc, tmp);
+}
+
+int
+ircquit(Irc *irc, char *why)
+{+ return ircrawf(irc, "QUIT :%s", why);
+}
+
+int
+ircuser(Irc *irc, char *user, char *mode, char *realname)
+{+ return ircrawf(irc, "USER %s %s * :%s", user, mode, realname);
+}
+
+int
+ircnick(Irc *irc, char *nickname)
+{+ return ircrawf(irc, "NICK %s", nickname);
+}
+
+int
+ircjoin(Irc *irc, char *channel)
+{+ return ircrawf(irc, "JOIN %s", channel);
+}
+
+int
+ircpart(Irc *irc, char *channel)
+{+ return ircrawf(irc, "PART %s", channel);
+}
+
+int
+ircprivmsg(Irc *irc, char *tgt, char *msg)
+{+ return ircrawf(irc, "PRIVMSG %s :%s", tgt, msg);
+}
--- /dev/null
+++ b/libirc/irc.h
@@ -1,0 +1,50 @@
+typedef struct IrcConf IrcConf;
+typedef struct Irc Irc;
+#pragma incomplete Irc
+typedef struct IrcMsg IrcMsg;
+typedef struct IrcHooks IrcHooks;
+
+typedef void IrcCb(Irc*, IrcMsg*, void *aux);
+
+struct IrcConf
+{+ char *address;
+ int debug;
+ void *aux;
+ int (*dial)(Irc *irc, IrcConf *conf);
+};
+
+struct IrcMsg
+{+ char prefix[256];
+ char cmd[64];
+ char **args;
+ int nargs;
+};
+
+#define IRC_DISCONNECT "_DISCONNECTED"
+#define IRC_CONNECT "_CONNECTED"
+#define IRC_DIALING "_DIALING"
+#define IRC_OOM "_OOM"
+
+#define IRC_PING "PING"
+#define IRC_NOTICE "NOTICE"
+#define IRC_PRIVMSG "PRIVMSG"
+
+#define IRC_RPL_WELCOME "001"
+#define IRC_ERR_NICKNAMEINUSE "433"
+
+Irc* ircinit(IrcConf *conf);
+void ircfree(Irc*);
+int ircrun(Irc*);
+int irchook(Irc *irc, char *what, IrcCb *cb);
+void ircterminate(Irc *irc);
+IrcConf *ircconf(Irc*);
+int ircraw(Irc *irc, char *msg);
+int ircrawf(Irc *irc, char *fmt, ...);
+int ircquit(Irc *irc, char *why);
+int ircuser(Irc *irc, char *user, char *mode, char *realname);
+int ircnick(Irc *irc, char *nickname);
+int ircjoin(Irc *irc, char *channel);
+int ircpart(Irc *irc, char *channel);
+int ircprivmsg(Irc *irc, char *tgt, char *msg);
--- /dev/null
+++ b/libirc/mkfile
@@ -1,0 +1,20 @@
+</$objtype/mkfile
+
+P=irc
+
+LIB=lib$P.$O.a
+OFILES=$P.$O
+HFILES=/sys/include/$P.h
+
+</sys/src/cmd/mklib
+
+install:V: $LIB
+ cp $LIB /$objtype/lib/lib$P.a
+ cp $P.h /sys/include/$P.h
+ #cp $P.man2 /sys/man/2/$P
+
+uninstall:V:
+ rm -f /$objtype/lib/lib$P.a /sys/include/$P.h /sys/man/2/$P
+
+$O.test: test.$O $LIB
+ $LD -o $target $prereq
--- /dev/null
+++ b/netsurf/layout.c
@@ -1,0 +1,221 @@
+#include <draw.h>
+#include <ctype.h>
+#include "utils/nsoption.h"
+#include "netsurf/inttypes.h"
+#include "netsurf/layout.h"
+#include "netsurf/plot_style.h"
+#include "utils/utf8.h"
+#include "plan9/layout.h"
+#include "plan9/utils.h"
+
+/* from mothra */
+struct font_definitions {+ char *name;
+ Font *font;
+} fontlist[4][4] = {+ "lucidasans/unicode.7", 0,
+ "lucidasans/unicode.8", 0,
+ "lucidasans/unicode.10", 0,
+ "lucidasans/unicode.13", 0,
+
+ "lucidasans/italicunicode.7", 0,
+ "lucidasans/italicunicode.8", 0,
+ "lucidasans/italicunicode.10", 0,
+ "lucidasans/italicunicode.13", 0,
+
+ "lucidasans/boldunicode.7", 0,
+ "lucidasans/boldunicode.8", 0,
+ "lucidasans/boldunicode.10", 0,
+ "lucidasans/boldunicode.13", 0,
+
+ "pelm/unicode.9", 0,
+ "pelm/unicode.9", 0,
+ "pelm/unicode.9", 0,
+ "pelm/unicode.9", 0,
+};
+
+enum
+{+ FONT_SIZE_SMALL = 0,
+ FONT_SIZE_MEDIUM,
+ FONT_SIZE_LARGE,
+ FONT_SIZE_HUGE,
+};
+
+enum
+{+ FONT_NORMAL = 0,
+ FONT_ITALIC,
+ FONT_BOLD,
+ FONT_MONO
+};
+
+/**
+ * \brief Convert a netsurf font description to a Plan 9 font
+ *
+ * \param fstyle The font style description
+ * \return A matching font on success or the default system font
+ */
+Font* getfont(const plot_font_style_t *fstyle)
+{+ int s, t, size;
+ char buf[255];
+
+ size = fstyle->size / PLOT_STYLE_SCALE;
+ if(size < 9)
+ s = FONT_SIZE_SMALL;
+ else if(size < 13)
+ s = FONT_SIZE_MEDIUM;
+ else if(size < 17)
+ s = FONT_SIZE_LARGE;
+ else
+ s = FONT_SIZE_HUGE;
+
+ if(fstyle->weight >= 500)
+ t = FONT_BOLD;
+ else if(fstyle->family == PLOT_FONT_FAMILY_MONOSPACE)
+ t = FONT_MONO;
+ else if(fstyle->flags == FONTF_ITALIC || fstyle->flags == FONTF_OBLIQUE)
+ t = FONT_ITALIC;
+ else
+ t = FONT_NORMAL;
+
+ if(fontlist[t][s].font == 0) {+ snprintf(buf, sizeof buf, "/lib/font/bit/%s.font", fontlist[t][s].name);
+ fontlist[t][s].font = openfont(display, buf);
+ if(fontlist[t][s].font==0)
+ fontlist[t][s].font=font;
+ }
+ return fontlist[t][s].font;
+}
+
+/**
+ * Measure the width of a string.
+ *
+ * \param[in] fstyle plot style for this text
+ * \param[in] string UTF-8 string to measure
+ * \param[in] length length of string, in bytes
+ * \param[out] width updated to width of string[0..length)
+ * \return NSERROR_OK and width updated or appropriate error
+ * code on faliure
+ */
+nserror
+layout_width(const struct plot_font_style *fstyle, const char *s, size_t length, int *width)
+{+ Font *f;
+ uint32_t ucs4;
+ size_t nxtchr = 0;
+
+ f = getfont(fstyle);
+ *width = 0;
+ while (nxtchr < length) {+ ucs4 = utf8_to_ucs4(s + nxtchr, length - nxtchr);
+ nxtchr = utf8_next(s, length, nxtchr);
+
+ *width += runestringnwidth(f, &ucs4, 1);
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find the position in a string where an x coordinate falls.
+ *
+ * \param[in] fstyle style for this text
+ * \param[in] string UTF-8 string to measure
+ * \param[in] length length of string, in bytes
+ * \param[in] x coordinate to search for
+ * \param[out] char_offset updated to offset in string of actual_x, [0..length]
+ * \param[out] actual_x updated to x coordinate of character closest to x
+ * \return NSERROR_OK and char_offset and actual_x updated or appropriate error code on faliure
+ */
+nserror
+layout_position(const struct plot_font_style *fstyle, const char *s, size_t length, int x, size_t *char_offset, int *actual_x)
+{+ Font *f;
+ uint32_t ucs4;
+ size_t nxtchr = 0;
+ int prev_x = 0;
+
+ f = getfont(fstyle);
+ *actual_x = 0;
+ while (nxtchr < length) {+ ucs4 = utf8_to_ucs4(s + nxtchr, length - nxtchr);
+
+ *actual_x += runestringnwidth(f, &ucs4, 1);
+ if (*actual_x > x)
+ break;
+
+ prev_x = *actual_x;
+ nxtchr = utf8_next(s, length, nxtchr);
+ }
+
+ /* choose nearest of previous and last x */
+ if (abs(*actual_x - x) > abs(prev_x - x))
+ *actual_x = prev_x;
+
+ *char_offset = nxtchr;
+ return NSERROR_OK;}
+
+
+/**
+ * Find where to split a string to make it fit a width.
+ *
+ * \param[in] fstyle style for this text
+ * \param[in] string UTF-8 string to measure
+ * \param[in] length length of string, in bytes
+ * \param[in] x width available
+ * \param[out] char_offset updated to offset in string of actual_x, [1..length]
+ * \param[out] actual_x updated to x coordinate of character closest to x
+ * \return NSERROR_OK or appropriate error code on faliure
+ *
+ * On exit, char_offset indicates first character after split point.
+ *
+ * \note char_offset of 0 must never be returned.
+ *
+ * Returns:
+ * char_offset giving split point closest to x, where actual_x <= x
+ * else
+ * char_offset giving split point closest to x, where actual_x > x
+ *
+ * Returning char_offset == length means no split possible
+ */
+nserror
+layout_split(const struct plot_font_style *fstyle, const char *s, size_t length, int x, size_t *char_offset, int *actual_x)
+{+ Font *f;
+ uint32_t ucs4;
+ size_t nxtchr = 0;
+ int last_space_x = 0;
+ int last_space_idx = 0;
+
+ f = getfont(fstyle);
+ *actual_x = 0;
+ while (nxtchr < length) {+ ucs4 = utf8_to_ucs4(s + nxtchr, length - nxtchr);
+
+ if (ucs4 == ' ' || ucs4 == '\t') {+ last_space_x = *actual_x;
+ last_space_idx = nxtchr;
+ }
+
+ *actual_x += runestringnwidth(f, &ucs4, 1);
+ if (*actual_x > x && last_space_idx != 0) {+ *actual_x = last_space_x;
+ *char_offset = last_space_idx;
+ return NSERROR_OK;
+ }
+
+ nxtchr = utf8_next(s, length, nxtchr);
+ }
+ *char_offset = length;
+ return NSERROR_OK;
+}
+
+static struct gui_layout_table layout_table = {+ .width = layout_width,
+ .position = layout_position,
+ .split = layout_split,
+};
+
+struct gui_layout_table *plan9_layout_table = &layout_table;
--- /dev/null
+++ b/pelm/unicode.10.font
@@ -1,0 +1,166 @@
+17 14
+0x0000 0x007f ascii.10
+0xfff9 0xffff ../dejavu/dejavu.14.fff9
+0xfb00 0xfc00 ../dejavu/dejavu.14.fb00
+0xf6c5 0xf7c5 ../dejavu/dejavu.14.f6c5
+0xf400 0xf500 ../dejavu/dejavu.14.f400
+0xa746 0xa846 ../dejavu/dejavu.14.a746
+0xa644 0xa744 ../dejavu/dejavu.14.a644
+0x2e18 0x2f18 ../dejavu/dejavu.14.2e18
+0x2c60 0x2d60 ../dejavu/dejavu.14.2c60
+0x2b00 0x2c00 ../dejavu/dejavu.14.2b00
+0x29eb 0x2aeb ../dejavu/dejavu.14.29eb
+0x28a2 0x29a2 ../dejavu/dejavu.14.28a2
+0x27a1 0x28a1 ../dejavu/dejavu.14.27a1
+0x2524 0x2624 ../dejavu/dejavu.14.2524
+0x2423 0x2523 ../dejavu/dejavu.14.2423
+0x1e01 0x1f01 ../dejavu/dejavu.14.1e01
+0x1d00 0x1e00 ../dejavu/dejavu.14.1d00
+0x10a0 0x11a0 ../dejavu/dejavu.14.10a0
+0x0101 0x0201 ../dejavu/dejavu.14.0101
+0x0000 0x0100 ../dejavu/dejavu.14.0000
+0xfe00 0xfeff ../dejavusans/dejavusans.14.fe00
+0xf001 0xf101 ../dejavusans/dejavusans.14.f001
+0xef00 0xf000 ../dejavusans/dejavusans.14.ef00
+0x4dc0 0x4ec0 ../dejavusans/dejavusans.14.4dc0
+0x2d61 0x2e61 ../dejavusans/dejavusans.14.2d61
+0x2104 0x21fb ../dejavusans/dejavusans.14.2104
+0x2100 0x2103 ../dejavusans/dejavusans.14.2003
+0x1f02 0x2002 ../dejavusans/dejavusans.14.1f02
+0x1401 0x1501 ../dejavusans/dejavusans.14.1401
+0x0f00 0x0f3f ../dejavusans/dejavusans.14.0e3f
+0x0404 0x0504 ../dejavusans/dejavusans.14.0404
+0x03c0 0x03c0 ../dejavusans/dejavusans.14.03c0
+0x03a9 0x03a9 ../dejavusans/dejavusans.14.03a9
+0x0303 0x0403 ../dejavusans/dejavusans.14.0303
+0x0202 0x02ff ../dejavusans/dejavusans.14.0202
+0x3000 0x30fe ../shinonome/k14.3000
+0x4e00 0x4ffe ../shinonome/k14.4e00
+0x5005 0x51fe ../shinonome/k14.5005
+0x5200 0x53fa ../shinonome/k14.5200
+0x5401 0x55fe ../shinonome/k14.5401
+0x5606 0x57fc ../shinonome/k14.5606
+0x5800 0x59ff ../shinonome/k14.5800
+0x5a01 0x5bff ../shinonome/k14.5a01
+0x5c01 0x5dfe ../shinonome/k14.5c01
+0x5e02 0x5fff ../shinonome/k14.5e02
+0x600e 0x61ff ../shinonome/k14.600e
+0x6200 0x63fa ../shinonome/k14.6200
+0x6406 0x65fb ../shinonome/k14.6406
+0x6602 0x67ff ../shinonome/k14.6602
+0x6802 0x69ff ../shinonome/k14.6802
+0x6a02 0x6bf3 ../shinonome/k14.6a02
+0x6c08 0x6dfb ../shinonome/k14.6c08
+0x6e05 0x6ffe ../shinonome/k14.6e05
+0x7001 0x71ff ../shinonome/k14.7001
+0x7206 0x73fe ../shinonome/k14.7206
+0x7403 0x75ff ../shinonome/k14.7403
+0x7601 0x77fc ../shinonome/k14.7601
+0x7802 0x79fb ../shinonome/k14.7802
+0x7a00 0x7bf7 ../shinonome/k14.7a00
+0x7c00 0x7dfb ../shinonome/k14.7c00
+0x7e01 0x7ffc ../shinonome/k14.7e01
+0x8000 0x81fe ../shinonome/k14.8000
+0x8201 0x83fd ../shinonome/k14.8201
+0x8403 0x85fe ../shinonome/k14.8403
+0x8602 0x87fe ../shinonome/k14.8602
+0x8805 0x89f8 ../shinonome/k14.8805
+0x8a00 0x8b9a ../shinonome/k14.8a00
+0x8c37 0x8dff ../shinonome/k14.8c37
+0x8e08 0x8ffd ../shinonome/k14.8e08
+0x9000 0x91ff ../shinonome/k14.9000
+0x920d 0x93e8 ../shinonome/k14.920d
+0x9403 0x95e5 ../shinonome/k14.9403
+0x961c 0x97ff ../shinonome/k14.961c
+0x9801 0x99ff ../shinonome/k14.9801
+0x9a01 0x9bf5 ../shinonome/k14.9a01
+0x9c04 0x9dfd ../shinonome/k14.9c04
+0x9e1a 0x9fa0 ../shinonome/k14.9e1a
+0x0500 0x05ff ../fixed/10x20.0500
+0x0600 0x06ff ../fixed/10x20.0600
+0x0e00 0x0eff ../fixed/10x20.0E00
+0x1000 0x10ff ../fixed/10x20.1000
+0x1200 0x12ff ../fixed/10x20.1200
+0x1300 0x13ff ../fixed/10x20.1300
+0x1600 0x16ff ../fixed/10x20.1600
+0x2000 0x2044 ../misc/genpunc.9
+0x2070 0x208e ../pelm/supsub.9
+0x20a0 0x20ac ../pelm/currency.9
+0x2200 0x227f ../misc/math1
+0x2280 0x22f1 ../misc/math2
+0x2300 0x232c ../misc/tech
+0x2600 0x266f ../misc/ding
+0x2700 0x27bf ../misc/zapf
+0x2a00 0x2aff ../fixed/10x20.2A00
+0x4d00 0x4dff ../fixed/10x20.4D00
+0x4e00 0x4fff ../jis/jis4e00.16
+0x5000 0x51ff ../jis/jis5000.16
+0x5200 0x53ff ../jis/jis5200.16
+0x5400 0x55ff ../jis/jis5400.16
+0x5600 0x57ff ../jis/jis5600.16
+0x5a00 0x5bff ../jis/jis5a00.16
+0x5c00 0x5dff ../jis/jis5c00.16
+0x5e00 0x5fff ../jis/jis5e00.16
+0x6000 0x61ff ../jis/jis6000.16
+0x6200 0x63ff ../jis/jis6200.16
+0x6400 0x65ff ../jis/jis6400.16
+0x6600 0x67ff ../jis/jis6600.16
+0x6800 0x69ff ../jis/jis6800.16
+0x6a00 0x6bff ../jis/jis6a00.16
+0x6c00 0x6dff ../jis/jis6c00.16
+0x6e00 0x6fff ../jis/jis6e00.16
+0x7000 0x71ff ../jis/jis7000.16
+0x7200 0x73ff ../jis/jis7200.16
+0x7400 0x75ff ../jis/jis7400.16
+0x7600 0x77ff ../jis/jis7600.16
+0x7800 0x79ff ../jis/jis7800.16
+0x7a00 0x7bff ../jis/jis7a00.16
+0x7c00 0x7dff ../jis/jis7c00.16
+0x7e00 0x7fff ../jis/jis7e00.16
+0x8000 0x81ff ../jis/jis8000.16
+0x8200 0x83ff ../jis/jis8200.16
+0x8400 0x85ff ../jis/jis8400.16
+0x8600 0x87ff ../jis/jis8600.16
+0x8800 0x89ff ../jis/jis8800.16
+0x8a00 0x8bff ../jis/jis8a00.16
+0x8c00 0x8dff ../jis/jis8c00.16
+0x8e00 0x8fff ../jis/jis8e00.16
+0x9200 0x93ff ../jis/jis9200.16
+0x9400 0x95ff ../jis/jis9400.16
+0x9600 0x97ff ../jis/jis9600.16
+0x9800 0x99ff ../jis/jis9800.16
+0x9a00 0x9bff ../jis/jis9a00.16
+0x9c00 0x9dff ../jis/jis9c00.16
+0x9e00 0x9fff ../jis/jis9e00.16
+0xfc00 0xfcff ../fixed/10x20.FC00
+0xfd00 0xfdff ../fixed/10x20.FD00
+0xfee0 0xff5e ../pelm/latin1.9
+0x0300 0x03ff ../fixed/10x20.0300
+0x2000 0x20ff ../fixed/10x20.2000
+0x2100 0x21ff ../fixed/10x20.2100
+0x2200 0x22ff ../fixed/10x20.2200
+0x2300 0x23ff ../fixed/10x20.2300
+0x2400 0x24ff ../fixed/10x20.2400
+0x2600 0x26ff ../fixed/10x20.2600
+0xff00 0xffff ../fixed/10x20.FF00
+0x1400 0x14ff ../fixed/9x18.1400
+0x1500 0x15ff ../fixed/9x18.1500
+0x2940 0x2a40 ../dejavusans/dejavusans.12.2940
+0x07c0 0x08c0 ../dejavusans/dejavusans.12.07c0
+0x0606 0x0706 ../dejavusans/dejavusans.12.0606
+0xe000 0xe0ff ../fixed/9x15.E000
+0xe700 0xe7ff ../fixed/9x15.E700
+0x1100 0x11ff ../fixed/6x13.1100
+0xf6c4 0xf7c4 ../dejavubi/dejavubi.14.f6c4
+0xf5c5 0xf6c5 ../dejavusansbi/dejavusansbi.14.f5c5
+0xf101 0xf201 ../germgoth/germgoth.16.f101
+0x3000 0x30ff ../fixed/10x20.3000
+0x1700 0x1746 ../dejavusansit/dejavusansit.12.1646
+0x3130 0x318f ../source/hansans.10.3130-318f
+0xac00 0xb3ff ../source/hansans.10.ac00-b3ff
+0xb400 0xbbff ../source/hansans.10.b400-bbff
+0xbc00 0xc3ff ../source/hansans.10.bc00-c3ff
+0xc400 0xcbff ../source/hansans.10.c400-cbff
+0xcc00 0xd3ff ../source/hansans.10.cc00-d3ff
+0xd400 0xd7a3 ../source/hansans.10.d400-d7a3
+0x00a0 0x021f ../vga/vga.00A0-021F
--- /dev/null
+++ b/pelm/unicode.12.font
@@ -1,0 +1,154 @@
+22 18
+0x0000 0x007f ascii.12
+0xfff9 0xffff ../dejavu/dejavu.18.fff9
+0xfb00 0xfc00 ../dejavu/dejavu.18.fb00
+0xf6c5 0xf7c5 ../dejavu/dejavu.18.f6c5
+0xf400 0xf500 ../dejavu/dejavu.18.f400
+0xa746 0xa846 ../dejavu/dejavu.18.a746
+0xa644 0xa744 ../dejavu/dejavu.18.a644
+0x2e18 0x2f18 ../dejavu/dejavu.18.2e18
+0x2c60 0x2d60 ../dejavu/dejavu.18.2c60
+0x2b00 0x2c00 ../dejavu/dejavu.18.2b00
+0x28a2 0x29a2 ../dejavu/dejavu.18.28a2
+0x27a1 0x28a1 ../dejavu/dejavu.18.27a1
+0x1e01 0x1f01 ../dejavu/dejavu.18.1e01
+0x1d00 0x1e00 ../dejavu/dejavu.18.1d00
+0x10a0 0x11a0 ../dejavu/dejavu.18.10a0
+0x0101 0x0201 ../dejavu/dejavu.18.0101
+0x0000 0x0100 ../dejavu/dejavu.18.0000
+0xfe00 0xfeff ../dejavusans/dejavusans.18.fe00
+0xf001 0xf101 ../dejavusans/dejavusans.18.f001
+0xef00 0xf000 ../dejavusans/dejavusans.18.ef00
+0x4dc0 0x4ec0 ../dejavusans/dejavusans.18.4dc0
+0x2d61 0x2e61 ../dejavusans/dejavusans.18.2d61
+0x1401 0x1501 ../dejavusans/dejavusans.18.1401
+0x0f00 0x0f3f ../dejavusans/dejavusans.18.0e3f
+0x07c0 0x08c0 ../dejavusans/dejavusans.18.07c0
+0x03c0 0x03c0 ../dejavusans/dejavusans.18.03c0
+0x03a9 0x03a9 ../dejavusans/dejavusans.18.03a9
+0x3000 0x30fe ../shinonome/k16.3000
+0x4e00 0x4ffe ../shinonome/k16.4e00
+0x5005 0x51fe ../shinonome/k16.5005
+0x5200 0x53fa ../shinonome/k16.5200
+0x5401 0x55fe ../shinonome/k16.5401
+0x5606 0x57fc ../shinonome/k16.5606
+0x5800 0x59ff ../shinonome/k16.5800
+0x5a01 0x5bff ../shinonome/k16.5a01
+0x5c01 0x5dfe ../shinonome/k16.5c01
+0x5e02 0x5fff ../shinonome/k16.5e02
+0x600e 0x61ff ../shinonome/k16.600e
+0x6200 0x63fa ../shinonome/k16.6200
+0x6406 0x65fb ../shinonome/k16.6406
+0x6602 0x67ff ../shinonome/k16.6602
+0x6802 0x69ff ../shinonome/k16.6802
+0x6a02 0x6bf3 ../shinonome/k16.6a02
+0x6c08 0x6dfb ../shinonome/k16.6c08
+0x6e05 0x6ffe ../shinonome/k16.6e05
+0x7001 0x71ff ../shinonome/k16.7001
+0x7206 0x73fe ../shinonome/k16.7206
+0x7403 0x75ff ../shinonome/k16.7403
+0x7601 0x77fc ../shinonome/k16.7601
+0x7802 0x79fb ../shinonome/k16.7802
+0x7a00 0x7bf7 ../shinonome/k16.7a00
+0x7c00 0x7dfb ../shinonome/k16.7c00
+0x7e01 0x7ffc ../shinonome/k16.7e01
+0x8000 0x81fe ../shinonome/k16.8000
+0x8201 0x83fd ../shinonome/k16.8201
+0x8403 0x85fe ../shinonome/k16.8403
+0x8602 0x87fe ../shinonome/k16.8602
+0x8805 0x89f8 ../shinonome/k16.8805
+0x8a00 0x8b9a ../shinonome/k16.8a00
+0x8c37 0x8dff ../shinonome/k16.8c37
+0x8e08 0x8ffd ../shinonome/k16.8e08
+0x9000 0x91ff ../shinonome/k16.9000
+0x920d 0x93e8 ../shinonome/k16.920d
+0x9403 0x95e5 ../shinonome/k16.9403
+0x961c 0x97ff ../shinonome/k16.961c
+0x9801 0x99ff ../shinonome/k16.9801
+0x9a01 0x9bf5 ../shinonome/k16.9a01
+0x9c04 0x9dfd ../shinonome/k16.9c04
+0x9e1a 0x9fa0 ../shinonome/k16.9e1a
+0x4e00 0x4fff ../jis/jis4e00.24
+0x5000 0x51ff ../jis/jis5000.24
+0x5200 0x53ff ../jis/jis5200.24
+0x5400 0x55ff ../jis/jis5400.24
+0x5600 0x57ff ../jis/jis5600.24
+0x5a00 0x5bff ../jis/jis5a00.24
+0x5c00 0x5dff ../jis/jis5c00.24
+0x5e00 0x5fff ../jis/jis5e00.24
+0x6000 0x61ff ../jis/jis6000.24
+0x6200 0x63ff ../jis/jis6200.24
+0x6400 0x65ff ../jis/jis6400.24
+0x6600 0x67ff ../jis/jis6600.24
+0x6800 0x69ff ../jis/jis6800.24
+0x6a00 0x6bff ../jis/jis6a00.24
+0x6c00 0x6dff ../jis/jis6c00.24
+0x6e00 0x6fff ../jis/jis6e00.24
+0x7000 0x71ff ../jis/jis7000.24
+0x7200 0x73ff ../jis/jis7200.24
+0x7400 0x75ff ../jis/jis7400.24
+0x7600 0x77ff ../jis/jis7600.24
+0x7800 0x79ff ../jis/jis7800.24
+0x7a00 0x7bff ../jis/jis7a00.24
+0x7c00 0x7dff ../jis/jis7c00.24
+0x7e00 0x7fff ../jis/jis7e00.24
+0x8000 0x81ff ../jis/jis8000.24
+0x8200 0x83ff ../jis/jis8200.24
+0x8400 0x85ff ../jis/jis8400.24
+0x8600 0x87ff ../jis/jis8600.24
+0x8800 0x89ff ../jis/jis8800.24
+0x8a00 0x8bff ../jis/jis8a00.24
+0x8c00 0x8dff ../jis/jis8c00.24
+0x8e00 0x8fff ../jis/jis8e00.24
+0x9200 0x93ff ../jis/jis9200.24
+0x9400 0x95ff ../jis/jis9400.24
+0x9600 0x97ff ../jis/jis9600.24
+0x9800 0x99ff ../jis/jis9800.24
+0x9a00 0x9bff ../jis/jis9a00.24
+0x9c00 0x9dff ../jis/jis9c00.24
+0x9e00 0x9fff ../jis/jis9e00.24
+0x0200 0x02ff ../fixed/6x10.0200
+0x0300 0x03ff ../fixed/6x10.0300
+0x0400 0x04ff ../fixed/6x10.0400
+0x0500 0x05ff ../fixed/6x10.0500
+0x1600 0x16ff ../fixed/6x10.1600
+0x1f00 0x1fff ../fixed/6x10.1F00
+0x2000 0x20ff ../fixed/6x10.2000
+0x2100 0x21ff ../fixed/6x10.2100
+0x2200 0x22ff ../fixed/6x10.2200
+0x2300 0x23ff ../fixed/6x10.2300
+0x2400 0x24ff ../fixed/6x10.2400
+0x2500 0x25ff ../fixed/6x10.2500
+0x2600 0x26ff ../fixed/6x10.2600
+0xff00 0xffff ../fixed/6x10.FF00
+0x2700 0x27bf ../misc/zapf
+0x0600 0x06ff ../fixed/10x20.0600
+0x0e00 0x0eff ../fixed/10x20.0E00
+0x1000 0x10ff ../fixed/10x20.1000
+0x1200 0x12ff ../fixed/10x20.1200
+0x1300 0x13ff ../fixed/10x20.1300
+0x2a00 0x2aff ../fixed/10x20.2A00
+0x4d00 0x4dff ../fixed/10x20.4D00
+0xfc00 0xfcff ../fixed/10x20.FC00
+0xfd00 0xfdff ../fixed/10x20.FD00
+0x29eb 0x2aeb ../dejavu/dejavu.14.29eb
+0x1400 0x14ff ../fixed/9x18.1400
+0x1500 0x15ff ../fixed/9x18.1500
+0x2940 0x2a40 ../dejavusans/dejavusans.12.2940
+0x0606 0x0706 ../dejavusans/dejavusans.12.0606
+0xe000 0xe0ff ../fixed/9x15.E000
+0xe700 0xe7ff ../fixed/9x15.E700
+0x1100 0x11ff ../fixed/6x13.1100
+0xf6c4 0xf7c4 ../dejavubi/dejavubi.18.f6c4
+0x1700 0x1746 ../dejavusansbd/dejavusansbd.18.1646
+0xf5c5 0xf6c5 ../dejavusansbi/dejavusansbi.18.f5c5
+0xf101 0xf201 ../germgoth/germgoth.18.f101
+0x3000 0x30ff ../fixed/10x20.3000
+0x3130 0x318f ../source/hansans.10.3130-318f
+0xac00 0xb3ff ../source/hansans.10.ac00-b3ff
+0xb400 0xbbff ../source/hansans.10.b400-bbff
+0xbc00 0xc3ff ../source/hansans.10.bc00-c3ff
+0xc400 0xcbff ../source/hansans.10.c400-cbff
+0xcc00 0xd3ff ../source/hansans.10.cc00-d3ff
+0xd400 0xd7a3 ../source/hansans.10.d400-d7a3
+0x00a0 0x021f ../vga/vga.00A0-021F
--- /dev/null
+++ b/pelm/unicode.16.font
@@ -1,0 +1,117 @@
+30 23
+0x0000 0x007f ascii.16
+0x0100 0x01f0 ../lucida/EuroLatin.14.0
+0x2000 0x20aa ../lucida/GenPunct.14.0
+0x2200 0x22f1 ../lucida/MathOps1.14.0
+0x3000 0x303f ../jis/jis3000.24
+0x30a1 0x30fe ../jis/katakana.24
+0x3041 0x309e ../jis/hiragana.24
+0x4e00 0x4fff ../jis/jis4e00.24
+0x5000 0x51ff ../jis/jis5000.24
+0x5200 0x53ff ../jis/jis5200.24
+0x5400 0x55ff ../jis/jis5400.24
+0x5600 0x57ff ../jis/jis5600.24
+0x5800 0x59ff ../jis/jis5800.24
+0x5a00 0x5bff ../jis/jis5a00.24
+0x5c00 0x5dff ../jis/jis5c00.24
+0x5e00 0x5fff ../jis/jis5e00.24
+0x6000 0x61ff ../jis/jis6000.24
+0x6200 0x63ff ../jis/jis6200.24
+0x6400 0x65ff ../jis/jis6400.24
+0x6600 0x67ff ../jis/jis6600.24
+0x6800 0x69ff ../jis/jis6800.24
+0x6a00 0x6bff ../jis/jis6a00.24
+0x6c00 0x6dff ../jis/jis6c00.24
+0x6e00 0x6fff ../jis/jis6e00.24
+0x7000 0x71ff ../jis/jis7000.24
+0x7200 0x73ff ../jis/jis7200.24
+0x7400 0x75ff ../jis/jis7400.24
+0x7600 0x77ff ../jis/jis7600.24
+0x7800 0x79ff ../jis/jis7800.24
+0x7a00 0x7bff ../jis/jis7a00.24
+0x7c00 0x7dff ../jis/jis7c00.24
+0x7e00 0x7fff ../jis/jis7e00.24
+0x8000 0x81ff ../jis/jis8000.24
+0x8200 0x83ff ../jis/jis8200.24
+0x8400 0x85ff ../jis/jis8400.24
+0x8600 0x87ff ../jis/jis8600.24
+0x8800 0x89ff ../jis/jis8800.24
+0x8a00 0x8bff ../jis/jis8a00.24
+0x8c00 0x8dff ../jis/jis8c00.24
+0x8e00 0x8fff ../jis/jis8e00.24
+0x9000 0x91ff ../jis/jis9000.24
+0x9200 0x93ff ../jis/jis9200.24
+0x9400 0x95ff ../jis/jis9400.24
+0x9600 0x97ff ../jis/jis9600.24
+0x9800 0x99ff ../jis/jis9800.24
+0x9a00 0x9bff ../jis/jis9a00.24
+0x9c00 0x9dff ../jis/jis9c00.24
+0x9e00 0x9fff ../jis/jis9e00.24
+0x0000 0x00ff ../fixed/9x18.0000
+0x0100 0x01ff ../fixed/9x18.0100
+0x0200 0x02ff ../fixed/9x18.0200
+0x0300 0x03ff ../fixed/9x18.0300
+0x0400 0x04ff ../fixed/9x18.0400
+0x0500 0x05ff ../fixed/9x18.0500
+0x0e00 0x0eff ../fixed/9x18.0E00
+0x1000 0x10ff ../fixed/9x18.1000
+0x1200 0x12ff ../fixed/9x18.1200
+0x1300 0x13ff ../fixed/9x18.1300
+0x1400 0x14ff ../fixed/9x18.1400
+0x1500 0x15ff ../fixed/9x18.1500
+0x1600 0x16ff ../fixed/9x18.1600
+0x1e00 0x1eff ../fixed/9x18.1E00
+0x1f00 0x1fff ../fixed/9x18.1F00
+0x2000 0x20ff ../fixed/9x18.2000
+0x2100 0x21ff ../fixed/9x18.2100
+0x2200 0x22ff ../fixed/9x18.2200
+0x2300 0x23ff ../fixed/9x18.2300
+0x2400 0x24ff ../fixed/9x18.2400
+0x2500 0x25ff ../fixed/9x18.2500
+0x2600 0x26ff ../fixed/9x18.2600
+0x2700 0x27ff ../fixed/9x18.2700
+0x2800 0x28ff ../fixed/9x18.2800
+0x2a00 0x2aff ../fixed/9x18.2A00
+0x3000 0x30fe ../shinonome/k14.3000
+0xfb00 0xfbff ../fixed/9x18.FB00
+0xfe00 0xfeff ../fixed/9x18.FE00
+0xff00 0xffff ../fixed/9x18.FF00
+0xfb00 0xfc00 ../dejavu/dejavu.12.fb00
+0xf6c5 0xf7c5 ../dejavu/dejavu.12.f6c5
+0xf400 0xf500 ../dejavu/dejavu.12.f400
+0xa746 0xa846 ../dejavu/dejavu.12.a746
+0xa644 0xa744 ../dejavu/dejavu.12.a644
+0x2e18 0x2f18 ../dejavu/dejavu.12.2e18
+0x2c60 0x2d60 ../dejavu/dejavu.12.2c60
+0x2b00 0x2c00 ../dejavu/dejavu.12.2b00
+0x29eb 0x2aeb ../dejavu/dejavu.12.29eb
+0x28a2 0x29a2 ../dejavu/dejavu.12.28a2
+0x1d00 0x1e00 ../dejavu/dejavu.12.1d00
+0x10a0 0x11a0 ../dejavu/dejavu.12.10a0
+0x0510 0x0610 ../dejavu/dejavu.12.0510
+0xf001 0xf101 ../dejavusans/dejavusans.12.f001
+0xef00 0xf000 ../dejavusans/dejavusans.12.ef00
+0x4dc0 0x4ec0 ../dejavusans/dejavusans.12.4dc0
+0x2d61 0x2e61 ../dejavusans/dejavusans.12.2d61
+0x2940 0x2a40 ../dejavusans/dejavusans.12.2940
+0x0f00 0x0f3f ../dejavusans/dejavusans.12.0e3f
+0x07c0 0x08c0 ../dejavusans/dejavusans.12.07c0
+0x0606 0x0706 ../dejavusans/dejavusans.12.0606
+0xe000 0xe0ff ../fixed/9x15.E000
+0xe700 0xe7ff ../fixed/9x15.E700
+0xfc00 0xfcff ../fixed/10x20.FC00
+0xfd00 0xfdff ../fixed/10x20.FD00
+0x1100 0x11ff ../fixed/6x13.1100
+0x4d00 0x4dff ../fixed/10x20.4D00
+0xf6c4 0xf7c4 ../dejavubi/dejavubi.12.f6c4
+0xf5c5 0xf6c5 ../dejavusansbi/dejavusansbi.12.f5c5
+0x1700 0x1746 ../dejavusansit/dejavusansit.12.1646
+0xf101 0xf201 ../germgoth/germgoth.14.f101
+0x3000 0x30ff ../fixed/10x20.3000
+0x3130 0x318f ../source/hansans.10.3130-318f
+0xac00 0xb3ff ../source/hansans.10.ac00-b3ff
+0xb400 0xbbff ../source/hansans.10.b400-bbff
+0xbc00 0xc3ff ../source/hansans.10.bc00-c3ff
+0xc400 0xcbff ../source/hansans.10.c400-cbff
+0xcc00 0xd3ff ../source/hansans.10.cc00-d3ff
+0xd400 0xd7a3 ../source/hansans.10.d400-d7a3
--
⑨